mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
Implemented the chain model for X.509 validation.
This commit is contained in:
parent
ebd36b6344
commit
74d344a521
@ -1,3 +1,7 @@
|
||||
2007-08-08 Werner Koch <wk@g10code.com>
|
||||
|
||||
* configure.ac: Use AC_CANONICAL_HOST and not AC_CANONICAL_TARGET.
|
||||
|
||||
2007-07-09 Werner Koch <wk@g10code.com>
|
||||
|
||||
* configure.ac (AM_ICONV): Check for it even when building without
|
||||
|
11
NEWS
11
NEWS
@ -1,11 +1,14 @@
|
||||
Noteworthy changes in version 2.0.6
|
||||
------------------------------------------------
|
||||
|
||||
* gpgsm does now grok --default-key.
|
||||
* GPGSM does now grok --default-key.
|
||||
|
||||
* GPGCONF is now aware of --default-key and --encrypt-to.
|
||||
|
||||
* GPGSM does again correctly print the serial number as well the the
|
||||
various keyids. This was broken since 2.0.4.
|
||||
|
||||
|
||||
* gpgconf is now aware of --default-key and --encrypt-to.
|
||||
|
||||
|
||||
Noteworthy changes in version 2.0.5 (2007-07-05)
|
||||
------------------------------------------------
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
2007-08-06 Werner Koch <wk@g10code.com>
|
||||
|
||||
* trustlist.c (read_one_trustfile): Add flag "cm".
|
||||
(agent_istrusted): Ditto.
|
||||
|
||||
2007-08-02 Werner Koch <wk@g10code.com>
|
||||
|
||||
* gpg-agent.c: Include gc-opt-flags.h and remove their definition
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* trustlist.c - Maintain the list of trusted keys
|
||||
* Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2002, 2004, 2006, 2007 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -42,6 +42,7 @@ struct trustitem_s
|
||||
int for_smime:1; /* Set by '*' or 'S' as first flag. */
|
||||
int relax:1; /* Relax checking of root certificate
|
||||
constraints. */
|
||||
int cm:1; /* Use chain model for validation. */
|
||||
} flags;
|
||||
unsigned char fpr[20]; /* The binary fingerprint. */
|
||||
};
|
||||
@ -267,6 +268,8 @@ read_one_trustfile (const char *fname, int allow_include,
|
||||
}
|
||||
else if (n == 5 && !memcmp (p, "relax", 5))
|
||||
ti->flags.relax = 1;
|
||||
else if (n == 2 && !memcmp (p, "cm", 2))
|
||||
ti->flags.cm = 1;
|
||||
else
|
||||
log_error ("flag `%.*s' in `%s', line %d ignored\n",
|
||||
n, p, fname, lnr);
|
||||
@ -396,6 +399,14 @@ agent_istrusted (ctrl_t ctrl, const char *fpr)
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
else if (ti->flags.cm)
|
||||
{
|
||||
err = agent_write_status (ctrl,
|
||||
"TRUSTLISTFLAG", "cm",
|
||||
NULL);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
return 0; /* Trusted. */
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,10 @@
|
||||
2007-08-07 Werner Koch <wk@g10code.com>
|
||||
|
||||
* tlv.c, tlv.h: Move from ../scd/.
|
||||
* tlv.c (parse_sexp, parse_ber_header): Add ERRSOURCE arg and prefix
|
||||
name with a _.
|
||||
* tlv.h: Use macro to convey ERRSOURCE.
|
||||
|
||||
2007-08-02 Werner Koch <wk@g10code.com>
|
||||
|
||||
* gc-opt-flags.h: New.
|
||||
@ -29,7 +36,7 @@
|
||||
|
||||
2007-07-04 Werner Koch <wk@g10code.com>
|
||||
|
||||
* estream.c (es_init_do): Do not throw an error if pth as already
|
||||
* estream.c (es_init_do): Do not throw an error if pth has already
|
||||
been initialized.
|
||||
|
||||
2007-06-26 Werner Koch <wk@g10code.com>
|
||||
|
@ -36,6 +36,7 @@ common_sources = \
|
||||
gc-opt-flags.h \
|
||||
keyserver.h \
|
||||
sexp-parse.h \
|
||||
tlv.c tlv.h \
|
||||
init.c init.h \
|
||||
sexputil.c \
|
||||
sysutils.c sysutils.h \
|
||||
|
@ -72,10 +72,10 @@ gnupg_get_isotime (gnupg_isotime_t timebuf)
|
||||
}
|
||||
|
||||
|
||||
/* set the time to NEWTIME so that gnupg_get_time returns a time
|
||||
/* Set the time to NEWTIME so that gnupg_get_time returns a time
|
||||
starting with this one. With FREEZE set to 1 the returned time
|
||||
will never change. Just for completeness, a value of (time_t)-1
|
||||
for NEWTIME gets you back to rality. Note that this is obviously
|
||||
for NEWTIME gets you back to reality. Note that this is obviously
|
||||
not thread-safe but this is not required. */
|
||||
void
|
||||
gnupg_set_time (time_t newtime, int freeze)
|
||||
@ -165,7 +165,7 @@ scan_isodatestr( const char *string )
|
||||
return stamp;
|
||||
}
|
||||
|
||||
/* Scan am ISO timestamp and return a epoch based timestamp. The only
|
||||
/* Scan am ISO timestamp and return an Epoch based timestamp. The only
|
||||
supported format is "yyyymmddThhmmss" delimited by white space, nul, a
|
||||
colon or a comma. Returns (time_t)(-1) for an invalid string. */
|
||||
time_t
|
||||
|
@ -29,7 +29,7 @@
|
||||
#define GPG_ERR_BAD_BER (1) /*G10ERR_GENERAL*/
|
||||
#define GPG_ERR_INV_SEXP (45) /*G10ERR_INV_ARG*/
|
||||
typedef int gpg_error_t;
|
||||
#define gpg_error(n) (n)
|
||||
#define gpg_make_err(x,n) (n)
|
||||
#else
|
||||
#include <gpg-error.h>
|
||||
#endif
|
||||
@ -151,10 +151,11 @@ find_tlv_unchecked (const unsigned char *buffer, size_t length,
|
||||
and the length part from the TLV triplet. Update BUFFER and SIZE
|
||||
on success. */
|
||||
gpg_error_t
|
||||
parse_ber_header (unsigned char const **buffer, size_t *size,
|
||||
int *r_class, int *r_tag,
|
||||
int *r_constructed, int *r_ndef,
|
||||
size_t *r_length, size_t *r_nhdr)
|
||||
_parse_ber_header (unsigned char const **buffer, size_t *size,
|
||||
int *r_class, int *r_tag,
|
||||
int *r_constructed, int *r_ndef,
|
||||
size_t *r_length, size_t *r_nhdr,
|
||||
gpg_err_source_t errsource)
|
||||
{
|
||||
int c;
|
||||
unsigned long tag;
|
||||
@ -167,7 +168,7 @@ parse_ber_header (unsigned char const **buffer, size_t *size,
|
||||
|
||||
/* Get the tag. */
|
||||
if (!length)
|
||||
return gpg_error (GPG_ERR_EOF);
|
||||
return gpg_err_make (errsource, GPG_ERR_EOF);
|
||||
c = *buf++; length--; ++*r_nhdr;
|
||||
|
||||
*r_class = (c & 0xc0) >> 6;
|
||||
@ -181,7 +182,7 @@ parse_ber_header (unsigned char const **buffer, size_t *size,
|
||||
{
|
||||
tag <<= 7;
|
||||
if (!length)
|
||||
return gpg_error (GPG_ERR_EOF);
|
||||
return gpg_err_make (errsource, GPG_ERR_EOF);
|
||||
c = *buf++; length--; ++*r_nhdr;
|
||||
tag |= c & 0x7f;
|
||||
|
||||
@ -192,7 +193,7 @@ parse_ber_header (unsigned char const **buffer, size_t *size,
|
||||
|
||||
/* Get the length. */
|
||||
if (!length)
|
||||
return gpg_error (GPG_ERR_EOF);
|
||||
return gpg_err_make (errsource, GPG_ERR_EOF);
|
||||
c = *buf++; length--; ++*r_nhdr;
|
||||
|
||||
if ( !(c & 0x80) )
|
||||
@ -200,20 +201,20 @@ parse_ber_header (unsigned char const **buffer, size_t *size,
|
||||
else if (c == 0x80)
|
||||
*r_ndef = 1;
|
||||
else if (c == 0xff)
|
||||
return gpg_error (GPG_ERR_BAD_BER);
|
||||
return gpg_err_make (errsource, GPG_ERR_BAD_BER);
|
||||
else
|
||||
{
|
||||
unsigned long len = 0;
|
||||
int count = c & 0x7f;
|
||||
|
||||
if (count > sizeof (len) || count > sizeof (size_t))
|
||||
return gpg_error (GPG_ERR_BAD_BER);
|
||||
return gpg_err_make (errsource, GPG_ERR_BAD_BER);
|
||||
|
||||
for (; count; count--)
|
||||
{
|
||||
len <<= 8;
|
||||
if (!length)
|
||||
return gpg_error (GPG_ERR_EOF);
|
||||
return gpg_err_make (errsource, GPG_ERR_EOF);
|
||||
c = *buf++; length--; ++*r_nhdr;
|
||||
len |= c & 0xff;
|
||||
}
|
||||
@ -254,8 +255,9 @@ parse_ber_header (unsigned char const **buffer, size_t *size,
|
||||
handle_error ();
|
||||
*/
|
||||
gpg_error_t
|
||||
parse_sexp (unsigned char const **buf, size_t *buflen,
|
||||
int *depth, unsigned char const **tok, size_t *toklen)
|
||||
_parse_sexp (unsigned char const **buf, size_t *buflen,
|
||||
int *depth, unsigned char const **tok, size_t *toklen,
|
||||
gpg_err_source_t errsource)
|
||||
{
|
||||
const unsigned char *s;
|
||||
size_t n, vlen;
|
||||
@ -265,7 +267,7 @@ parse_sexp (unsigned char const **buf, size_t *buflen,
|
||||
*tok = NULL;
|
||||
*toklen = 0;
|
||||
if (!n)
|
||||
return *depth ? gpg_error (GPG_ERR_INV_SEXP) : 0;
|
||||
return *depth ? gpg_err_make (errsource, GPG_ERR_INV_SEXP) : 0;
|
||||
if (*s == '(')
|
||||
{
|
||||
s++; n--;
|
||||
@ -277,7 +279,7 @@ parse_sexp (unsigned char const **buf, size_t *buflen,
|
||||
if (*s == ')')
|
||||
{
|
||||
if (!*depth)
|
||||
return gpg_error (GPG_ERR_INV_SEXP);
|
||||
return gpg_err_make (errsource, GPG_ERR_INV_SEXP);
|
||||
*toklen = 1;
|
||||
s++; n--;
|
||||
(*depth)--;
|
||||
@ -288,10 +290,10 @@ parse_sexp (unsigned char const **buf, size_t *buflen,
|
||||
for (vlen=0; n && *s && *s != ':' && (*s >= '0' && *s <= '9'); s++, n--)
|
||||
vlen = vlen*10 + (*s - '0');
|
||||
if (!n || *s != ':')
|
||||
return gpg_error (GPG_ERR_INV_SEXP);
|
||||
return gpg_err_make (errsource, GPG_ERR_INV_SEXP);
|
||||
s++; n--;
|
||||
if (vlen > n)
|
||||
return gpg_error (GPG_ERR_INV_SEXP);
|
||||
return gpg_err_make (errsource, GPG_ERR_INV_SEXP);
|
||||
*tok = s;
|
||||
*toklen = vlen;
|
||||
s += vlen;
|
@ -80,11 +80,14 @@ const unsigned char *find_tlv_unchecked (const unsigned char *buffer,
|
||||
/* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag
|
||||
and the length part from the TLV triplet. Update BUFFER and SIZE
|
||||
on success. */
|
||||
gpg_error_t parse_ber_header (unsigned char const **buffer, size_t *size,
|
||||
int *r_class, int *r_tag,
|
||||
int *r_constructed,
|
||||
int *r_ndef, size_t *r_length, size_t *r_nhdr);
|
||||
|
||||
gpg_error_t _parse_ber_header (unsigned char const **buffer, size_t *size,
|
||||
int *r_class, int *r_tag,
|
||||
int *r_constructed,
|
||||
int *r_ndef, size_t *r_length, size_t *r_nhdr,
|
||||
gpg_err_source_t errsource);
|
||||
#define parse_ber_header(a,b,c,d,e,f,g,h) \
|
||||
_parse_ber_header ((a),(b),(c),(d),(e),(f),(g),(h),\
|
||||
GPG_ERR_SOURCE_DEFAULT)
|
||||
|
||||
|
||||
/* Return the next token of an canconical encoded S-expression. BUF
|
||||
@ -99,8 +102,11 @@ gpg_error_t parse_ber_header (unsigned char const **buffer, size_t *size,
|
||||
reflect on return the actual depth of the tree. To detect the end
|
||||
of the S-expression it is advisable to check DEPTH after a
|
||||
successful return. */
|
||||
gpg_error_t parse_sexp (unsigned char const **buf, size_t *buflen,
|
||||
int *depth, unsigned char const **tok, size_t *toklen);
|
||||
gpg_error_t _parse_sexp (unsigned char const **buf, size_t *buflen,
|
||||
int *depth, unsigned char const **tok, size_t *toklen,
|
||||
gpg_err_source_t errsource);
|
||||
#define parse_sexp(a,b,c,d,e) \
|
||||
_parse_sexp ((a),(b),(c),(d),(e), GPG_ERR_SOURCE_DEFAULT)
|
||||
|
||||
|
||||
|
@ -112,7 +112,7 @@ const char *isotimestamp (u32 stamp); /* GMT */
|
||||
const char *asctimestamp (u32 stamp); /* localized */
|
||||
|
||||
|
||||
/* Copy one iso ddate to another, this is inline so that we can do a
|
||||
/* Copy one ISO date to another, this is inline so that we can do a
|
||||
sanity check. */
|
||||
static inline void
|
||||
gnupg_copy_time (gnupg_isotime_t d, const gnupg_isotime_t s)
|
||||
|
@ -56,8 +56,8 @@ VERSION=$PACKAGE_VERSION
|
||||
AC_CONFIG_AUX_DIR(scripts)
|
||||
AC_CONFIG_SRCDIR(sm/gpgsm.c)
|
||||
AM_CONFIG_HEADER(config.h)
|
||||
AC_CANONICAL_TARGET()
|
||||
AM_INIT_AUTOMAKE($PACKAGE, $VERSION)
|
||||
AC_CANONICAL_HOST
|
||||
AB_INIT
|
||||
|
||||
AC_GNU_SOURCE
|
||||
|
@ -1,3 +1,7 @@
|
||||
2007-08-09 Werner Koch <wk@g10code.com>
|
||||
|
||||
* gpgsm.texi (Certificate Options): Describe --validation-model.
|
||||
|
||||
2007-07-23 Werner Koch <wk@g10code.com>
|
||||
|
||||
* scdaemon.texi (Scdaemon Commands): Remove obsolete --print-atr.
|
||||
|
31
doc/DETAILS
31
doc/DETAILS
@ -253,8 +253,8 @@ more arguments in future versions.
|
||||
presence of the letter 'T' inside.
|
||||
|
||||
VALIDSIG <fingerprint in hex> <sig_creation_date> <sig-timestamp>
|
||||
<expire-timestamp> [ <sig-version> <reserved> <pubkey-algo>
|
||||
<hash-algo> <sig-class> <primary-key-fpr> ]
|
||||
<expire-timestamp> <sig-version> <reserved> <pubkey-algo>
|
||||
<hash-algo> <sig-class> [ <primary-key-fpr> ]
|
||||
|
||||
The signature with the keyid is good. This is the same as
|
||||
GOODSIG but has the fingerprint as the argument. Both status
|
||||
@ -269,8 +269,9 @@ more arguments in future versions.
|
||||
useful to get back to the primary key without running gpg
|
||||
again for this purpose.
|
||||
|
||||
The optional parameters are used for OpenPGP and are not
|
||||
available for CMS signatures.
|
||||
The primary-key-fpr parameter is used for OpenPGP and not
|
||||
available for CMS signatures. The sig-version as well as the
|
||||
sig class is not defined for CMS and currently set to 0 and 00.
|
||||
|
||||
Note, that *-TIMESTAMP may either be a number with seconds
|
||||
since epoch or an ISO 8601 string which can be detected by the
|
||||
@ -310,13 +311,21 @@ more arguments in future versions.
|
||||
|
||||
|
||||
TRUST_UNDEFINED <error token>
|
||||
TRUST_NEVER <error token>
|
||||
TRUST_MARGINAL
|
||||
TRUST_FULLY
|
||||
TRUST_ULTIMATE
|
||||
For good signatures one of these status lines are emitted
|
||||
to indicate how trustworthy the signature is. The error token
|
||||
values are currently only emitted by gpgsm.
|
||||
TRUST_NEVER <error token>
|
||||
TRUST_MARGINAL [0 [<validation_model>]]
|
||||
TRUST_FULLY [0 [<validation_model>]]
|
||||
TRUST_ULTIMATE [0 [<validation_model>]]
|
||||
For good signatures one of these status lines are emitted to
|
||||
indicate how trustworthy the signature is. The error token
|
||||
values are currently only emitted by gpgsm. VALIDATION_MODEL
|
||||
describes the algorithm used to check the validity of the key.
|
||||
The default is the standard gpg Web of Trust model respective
|
||||
the standard X.509 model. The defined values are
|
||||
|
||||
"pgp" for the standard PGP WoT.
|
||||
"shell" for the standard X.509 model.
|
||||
"chain" for the chain model.
|
||||
|
||||
|
||||
PKA_TRUST_GOOD <mailbox>
|
||||
PKA_TRUST_BAD <mailbox>
|
||||
|
@ -412,6 +412,17 @@ requests in Dirmngr's configuration too (option
|
||||
@option{--allow-ocsp} and configure dirmngr properly. If you don't do
|
||||
so you will get the error code @samp{Not supported}.
|
||||
|
||||
|
||||
@item --validation-model @var{name}
|
||||
@opindex validation-model
|
||||
This option changes the default validation model. The only possible
|
||||
values are "shell" (which is the default) and "chain" which forces the
|
||||
use of the chain model. The chain model is also used if an option in
|
||||
the @file{trustlist.txt} or an attribute of the certificate requests it.
|
||||
However the standard model (shell) is in that case always tried first.
|
||||
|
||||
|
||||
|
||||
@end table
|
||||
|
||||
@c *******************************************
|
||||
@ -550,7 +561,8 @@ encryption. For convenience the strings @code{3DES}, @code{AES} and
|
||||
@opindex faked-system-time
|
||||
This option is only useful for testing; it sets the system time back or
|
||||
forth to @var{epoch} which is the number of seconds elapsed since the year
|
||||
1970.
|
||||
1970. Alternativly @var{epoch} may be given as a full ISO time string
|
||||
(e.g. "20070924T154812").
|
||||
|
||||
@item --with-ephemeral-keys
|
||||
@opindex with-ephemeral-keys
|
||||
|
@ -122,7 +122,7 @@ This should return the Root cert of the issuer. See note above.
|
||||
|
||||
@item By exact match on serial number and issuer's DN.
|
||||
This is indicated by a hash mark, followed by the hexadecmal
|
||||
representation of the serial number, the followed by a slash and the
|
||||
representation of the serial number, then followed by a slash and the
|
||||
RFC-2253 encoded DN of the issuer. See note above.
|
||||
|
||||
@cartouche
|
||||
|
@ -1,3 +1,8 @@
|
||||
2007-08-09 Werner Koch <wk@g10code.com>
|
||||
|
||||
* argparse.c (show_help): Expand the @EMAIL@ macro in the package
|
||||
bug reporting address.
|
||||
|
||||
2007-08-02 Werner Koch <wk@g10code.com>
|
||||
|
||||
* t-stringhelp.c (test_compare_filenames): New.
|
||||
|
@ -832,8 +832,21 @@ show_help( ARGPARSE_OPTS *opts, unsigned flags )
|
||||
puts("\n(A single dash may be used instead of the double ones)");
|
||||
}
|
||||
if( (s=strusage(19)) ) { /* bug reports to ... */
|
||||
char *s2;
|
||||
|
||||
putchar('\n');
|
||||
fputs(s, stdout);
|
||||
s2 = strstr (s, "@EMAIL@");
|
||||
if (s2)
|
||||
{
|
||||
if (s2-s)
|
||||
fwrite (s, s2-s, 1, stdout);
|
||||
fputs (PACKAGE_BUGREPORT, stdout);
|
||||
s2 += 7;
|
||||
if (*s2)
|
||||
fputs (s2, stdout);
|
||||
}
|
||||
else
|
||||
fputs(s, stdout);
|
||||
}
|
||||
fflush(stdout);
|
||||
exit(0);
|
||||
|
1060
po/pt_BR.po
1060
po/pt_BR.po
File diff suppressed because it is too large
Load Diff
1050
po/zh_CN.po
1050
po/zh_CN.po
File diff suppressed because it is too large
Load Diff
1050
po/zh_TW.po
1050
po/zh_TW.po
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,7 @@
|
||||
2007-08-07 Werner Koch <wk@g10code.com>
|
||||
|
||||
* tlv.c, tlv.h: Move to ../common/.
|
||||
|
||||
2007-08-02 Werner Koch <wk@g10code.com>
|
||||
|
||||
* scdaemon.c: Include gc-opt-flags.h and remove their definition
|
||||
|
@ -38,7 +38,6 @@ scdaemon_SOURCES = \
|
||||
apdu.c apdu.h \
|
||||
ccid-driver.c ccid-driver.h \
|
||||
iso7816.c iso7816.h \
|
||||
tlv.c tlv.h \
|
||||
app.c app-common.h app-help.c $(card_apps)
|
||||
|
||||
|
||||
@ -55,7 +54,6 @@ scdaemon_LDADD = $(libcommonpth) ../jnlib/libjnlib.a ../gl/libgnu.a \
|
||||
# apdu.c apdu.h \
|
||||
# ccid-driver.c ccid-driver.h \
|
||||
# iso7816.c iso7816.h \
|
||||
# tlv.c tlv.h \
|
||||
# atr.c atr.h \
|
||||
# app.c app-common.h app-help.c $(card_apps)
|
||||
#
|
||||
|
62
sm/ChangeLog
62
sm/ChangeLog
@ -1,3 +1,65 @@
|
||||
2007-08-09 Werner Koch <wk@g10code.com>
|
||||
|
||||
* gpgsm.c (main) [W32]: Enable CRL check by default.
|
||||
(main): Update the default control structure after reading the
|
||||
options.
|
||||
(gpgsm_parse_validation_model, parse_validation_model): New.
|
||||
(main): New option --validation-model.
|
||||
* certchain.c (gpgsm_validate_chain): Implement this option.
|
||||
* server.c (option_handler): Ditto.
|
||||
|
||||
* certchain.c (is_cert_still_valid): Reformatted. Add arg
|
||||
FORCE_OCSP. Changed callers to set this flag when using the chain
|
||||
model.
|
||||
|
||||
2007-08-08 Werner Koch <wk@g10code.com>
|
||||
|
||||
* certdump.c (gpgsm_print_serial): Fixed brown paper bag style bugs
|
||||
which prefixed the output with a 3A and cut it off at a 00.
|
||||
|
||||
* keylist.c (list_cert_raw): Print the certificate ID first and
|
||||
rename "Serial number" to "S/N".
|
||||
(list_cert_std): Ditto.
|
||||
|
||||
2007-08-07 Werner Koch <wk@g10code.com>
|
||||
|
||||
* gpgsm.c (main): Allow a string for --faked-system-time.
|
||||
|
||||
2007-08-06 Werner Koch <wk@g10code.com>
|
||||
|
||||
Implementation of the chain model.
|
||||
|
||||
* gpgsm.h (struct rootca_flags_s): Define new members VALID and
|
||||
CHAIN_MODEL.
|
||||
* call-agent.c (gpgsm_agent_istrusted): Mark ROOTCA_FLAGS valid.
|
||||
(istrusted_status_cb): Set CHAIN_MODEL.
|
||||
* certchain.c (gpgsm_validate_chain): Replace LM alias by LISTMODE
|
||||
and FP by LISTFP.
|
||||
(gpgsm_validate_chain): Factor some code out to ...
|
||||
(check_validity_period, ask_marktrusted): .. new.
|
||||
(check_validity_cm_basic, check_validity_cm_main): New.
|
||||
(do_validate_chain): New with all code from gpgsm_validate_chain.
|
||||
New arg ROOTCA_FLAGS.
|
||||
(gpgsm_validate_chain): Provide ROOTCA_FLAGS and fallback to chain
|
||||
model. Add RETFLAGS arg and changed all callers to pass NULL. Add
|
||||
CHECKTIME arg and changed all callers to pass a nil value.
|
||||
(has_validity_model_chain): New.
|
||||
* verify.c (gpgsm_verify): Check for chain model and return as
|
||||
part of the trust status.
|
||||
|
||||
* gpgsm.h (VALIDATE_FLAG_NO_DIRMNGR): New.
|
||||
(VALIDATE_FLAG_NO_DIRMNGR): New.
|
||||
* call-dirmngr.c (gpgsm_dirmngr_isvalid): Use constant here.
|
||||
|
||||
2007-08-03 Werner Koch <wk@g10code.com>
|
||||
|
||||
* keylist.c (list_cert_colon): Avoid duplicate listing of kludge
|
||||
uids.
|
||||
|
||||
* verify.c (gpgsm_verify): Make STATUS_VERIFY return the hash and
|
||||
pk algo.
|
||||
* certcheck.c (gpgsm_check_cms_signature): Add arg R_PKALGO.
|
||||
|
||||
2007-08-02 Werner Koch <wk@g10code.com>
|
||||
|
||||
* gpgsm.c (main): Factored GC_OPT_FLAGS out to gc-opt-flags.h.
|
||||
|
@ -486,6 +486,8 @@ istrusted_status_cb (void *opaque, const char *line)
|
||||
;
|
||||
if (!strncmp (line, "relax", 5) && (line[5] == ' ' || !line[5]))
|
||||
flags->relax = 1;
|
||||
else if (!strncmp (line, "cm", 2) && (line[2] == ' ' || !line[2]))
|
||||
flags->chain_model = 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -521,6 +523,8 @@ gpgsm_agent_istrusted (ctrl_t ctrl, ksba_cert_t cert,
|
||||
|
||||
rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL,
|
||||
istrusted_status_cb, rootca_flags);
|
||||
if (!rc)
|
||||
rootca_flags->valid = 1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -394,8 +394,10 @@ isvalid_status_cb (void *opaque, const char *line)
|
||||
GPG_ERR_NO_CRL_KNOWN
|
||||
GPG_ERR_CRL_TOO_OLD
|
||||
|
||||
With USE_OCSP set to true, the dirmngr is asked to do an OCSP
|
||||
request first.
|
||||
Values for USE_OCSP:
|
||||
0 = Do CRL check.
|
||||
1 = Do an OCSP check.
|
||||
2 = Do an OCSP check using only the default responder.
|
||||
*/
|
||||
int
|
||||
gpgsm_dirmngr_isvalid (ctrl_t ctrl,
|
||||
@ -445,7 +447,8 @@ gpgsm_dirmngr_isvalid (ctrl_t ctrl,
|
||||
|
||||
/* FIXME: If --disable-crl-checks has been set, we should pass an
|
||||
option to dirmngr, so that no fallback CRL check is done after an
|
||||
ocsp check. */
|
||||
ocsp check. It is not a problem right now as dirmngr does not
|
||||
fallback to CRL checking. */
|
||||
|
||||
/* It is sufficient to send the options only once because we have
|
||||
one connection per process only. */
|
||||
@ -456,7 +459,9 @@ gpgsm_dirmngr_isvalid (ctrl_t ctrl,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
did_options = 1;
|
||||
}
|
||||
snprintf (line, DIM(line)-1, "ISVALID %s", certid);
|
||||
snprintf (line, DIM(line)-1, "ISVALID%s %s",
|
||||
use_ocsp == 2? " --only-ocsp --force-default-responder":"",
|
||||
certid);
|
||||
line[DIM(line)-1] = 0;
|
||||
xfree (certid);
|
||||
|
||||
@ -504,9 +509,10 @@ gpgsm_dirmngr_isvalid (ctrl_t ctrl,
|
||||
rc = gpg_error (GPG_ERR_INV_CRL);
|
||||
else
|
||||
{
|
||||
/* Note, the flag = 1: This avoids checking this
|
||||
certificate over and over again. */
|
||||
rc = gpgsm_validate_chain (ctrl, rspcert, NULL, 0, NULL, 1);
|
||||
/* Note the no_dirmngr flag: This avoids checking
|
||||
this certificate over and over again. */
|
||||
rc = gpgsm_validate_chain (ctrl, rspcert, "", NULL, 0, NULL,
|
||||
VALIDATE_FLAG_NO_DIRMNGR, NULL);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("invalid certificate used for CRL/OCSP: %s\n",
|
||||
|
686
sm/certchain.c
686
sm/certchain.c
@ -1,6 +1,6 @@
|
||||
/* certchain.c - certificate chain validation
|
||||
* Copyright (C) 2001, 2002, 2003, 2004, 2005,
|
||||
* 2006 Free Software Foundation, Inc.
|
||||
* 2006, 2007 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -37,6 +37,7 @@
|
||||
#include "keydb.h"
|
||||
#include "../kbx/keybox.h" /* for KEYBOX_FLAG_* */
|
||||
#include "i18n.h"
|
||||
#include "tlv.h"
|
||||
|
||||
|
||||
/* Object to keep track of certain root certificates. */
|
||||
@ -141,6 +142,71 @@ compare_certs (ksba_cert_t a, ksba_cert_t b)
|
||||
}
|
||||
|
||||
|
||||
/* Return true if CERT has the validityModel extensions and defines
|
||||
the use of the chain model. */
|
||||
static int
|
||||
has_validation_model_chain (ksba_cert_t cert, int listmode, estream_t listfp)
|
||||
{
|
||||
gpg_error_t err;
|
||||
int idx, yes;
|
||||
const char *oid;
|
||||
size_t off, derlen, objlen, hdrlen;
|
||||
const unsigned char *der;
|
||||
int class, tag, constructed, ndef;
|
||||
char *oidbuf;
|
||||
|
||||
for (idx=0; !(err=ksba_cert_get_extension (cert, idx,
|
||||
&oid, NULL, &off, &derlen));idx++)
|
||||
if (!strcmp (oid, "1.3.6.1.4.1.8301.3.5") )
|
||||
break;
|
||||
if (err)
|
||||
return 0; /* Not found. */
|
||||
der = ksba_cert_get_image (cert, NULL);
|
||||
if (!der)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_INV_OBJ); /* Oops */
|
||||
goto leave;
|
||||
}
|
||||
der += off;
|
||||
|
||||
err = parse_ber_header (&der, &derlen, &class, &tag, &constructed,
|
||||
&ndef, &objlen, &hdrlen);
|
||||
if (!err && (objlen > derlen || tag != TAG_SEQUENCE))
|
||||
err = gpg_error (GPG_ERR_INV_OBJ);
|
||||
if (err)
|
||||
goto leave;
|
||||
derlen = objlen;
|
||||
err = parse_ber_header (&der, &derlen, &class, &tag, &constructed,
|
||||
&ndef, &objlen, &hdrlen);
|
||||
if (!err && (objlen > derlen || tag != TAG_OBJECT_ID))
|
||||
err = gpg_error (GPG_ERR_INV_OBJ);
|
||||
if (err)
|
||||
goto leave;
|
||||
oidbuf = ksba_oid_to_str (der, objlen);
|
||||
if (!oidbuf)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (opt.verbose)
|
||||
do_list (0, listmode, listfp,
|
||||
_("validation model requested by certificate: %s"),
|
||||
!strcmp (oidbuf, "1.3.6.1.4.1.8301.3.5.1")? _("chain") :
|
||||
!strcmp (oidbuf, "1.3.6.1.4.1.8301.3.5.2")? _("shell") :
|
||||
/* */ oidbuf);
|
||||
yes = !strcmp (oidbuf, "1.3.6.1.4.1.8301.3.5.1");
|
||||
ksba_free (oidbuf);
|
||||
return yes;
|
||||
|
||||
|
||||
leave:
|
||||
log_error ("error parsing validityModel: %s\n", gpg_strerror (err));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
unknown_criticals (ksba_cert_t cert, int listmode, estream_t fp)
|
||||
{
|
||||
@ -155,6 +221,7 @@ unknown_criticals (ksba_cert_t cert, int listmode, estream_t fp)
|
||||
"2.5.29.19", /* basic Constraints */
|
||||
"2.5.29.32", /* certificatePolicies */
|
||||
"2.5.29.37", /* extendedKeyUsage - handled by certlist.c */
|
||||
"1.3.6.1.4.1.8301.3.5", /* validityModel - handled here. */
|
||||
NULL
|
||||
};
|
||||
int rc = 0, i, idx, crit;
|
||||
@ -653,73 +720,310 @@ gpgsm_is_root_cert (ksba_cert_t cert)
|
||||
|
||||
/* This is a helper for gpgsm_validate_chain. */
|
||||
static gpg_error_t
|
||||
is_cert_still_valid (ctrl_t ctrl, int lm, estream_t fp,
|
||||
is_cert_still_valid (ctrl_t ctrl, int force_ocsp, int lm, estream_t fp,
|
||||
ksba_cert_t subject_cert, ksba_cert_t issuer_cert,
|
||||
int *any_revoked, int *any_no_crl, int *any_crl_too_old)
|
||||
{
|
||||
if (!opt.no_crl_check || ctrl->use_ocsp)
|
||||
{
|
||||
gpg_error_t err;
|
||||
gpg_error_t err;
|
||||
|
||||
err = gpgsm_dirmngr_isvalid (ctrl,
|
||||
subject_cert, issuer_cert, ctrl->use_ocsp);
|
||||
if (err)
|
||||
if (opt.no_crl_check && !ctrl->use_ocsp)
|
||||
return 0;
|
||||
|
||||
err = gpgsm_dirmngr_isvalid (ctrl,
|
||||
subject_cert, issuer_cert,
|
||||
force_ocsp? 2 : !!ctrl->use_ocsp);
|
||||
if (err)
|
||||
{
|
||||
if (!lm)
|
||||
gpgsm_cert_log_name (NULL, subject_cert);
|
||||
switch (gpg_err_code (err))
|
||||
{
|
||||
/* Fixme: We should change the wording because we may
|
||||
have used OCSP. */
|
||||
case GPG_ERR_CERT_REVOKED:
|
||||
do_list (1, lm, fp, _("certificate has been revoked"));
|
||||
*any_revoked = 1;
|
||||
/* Store that in the keybox so that key listings are able to
|
||||
return the revoked flag. We don't care about error,
|
||||
though. */
|
||||
keydb_set_cert_flags (subject_cert, 1, KEYBOX_FLAG_VALIDITY, 0,
|
||||
~0, VALIDITY_REVOKED);
|
||||
break;
|
||||
|
||||
case GPG_ERR_NO_CRL_KNOWN:
|
||||
do_list (1, lm, fp, _("no CRL found for certificate"));
|
||||
*any_no_crl = 1;
|
||||
break;
|
||||
|
||||
case GPG_ERR_NO_DATA:
|
||||
do_list (1, lm, fp, _("the status of the certificate is unknown"));
|
||||
*any_no_crl = 1;
|
||||
break;
|
||||
|
||||
case GPG_ERR_CRL_TOO_OLD:
|
||||
do_list (1, lm, fp, _("the available CRL is too old"));
|
||||
if (!lm)
|
||||
gpgsm_cert_log_name (NULL, subject_cert);
|
||||
switch (gpg_err_code (err))
|
||||
{
|
||||
case GPG_ERR_CERT_REVOKED:
|
||||
do_list (1, lm, fp, _("certificate has been revoked"));
|
||||
*any_revoked = 1;
|
||||
/* Store that in the keybox so that key listings are
|
||||
able to return the revoked flag. We don't care
|
||||
about error, though. */
|
||||
keydb_set_cert_flags (subject_cert, 1, KEYBOX_FLAG_VALIDITY, 0,
|
||||
~0, VALIDITY_REVOKED);
|
||||
break;
|
||||
case GPG_ERR_NO_CRL_KNOWN:
|
||||
do_list (1, lm, fp, _("no CRL found for certificate"));
|
||||
*any_no_crl = 1;
|
||||
break;
|
||||
case GPG_ERR_CRL_TOO_OLD:
|
||||
do_list (1, lm, fp, _("the available CRL is too old"));
|
||||
if (!lm)
|
||||
log_info (_("please make sure that the "
|
||||
"\"dirmngr\" is properly installed\n"));
|
||||
*any_crl_too_old = 1;
|
||||
break;
|
||||
default:
|
||||
do_list (1, lm, fp, _("checking the CRL failed: %s"),
|
||||
gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
log_info (_("please make sure that the "
|
||||
"\"dirmngr\" is properly installed\n"));
|
||||
*any_crl_too_old = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
do_list (1, lm, fp, _("checking the CRL failed: %s"),
|
||||
gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Helper for gpgsm_validate_chain to check the validity period of
|
||||
SUBJECT_CERT. The caller needs to pass EXPTIME which will be
|
||||
updated to the nearest expiration time seen. A DEPTH of 0 indicates
|
||||
the target certifciate, -1 the final root certificate and other
|
||||
values intermediate certificates. */
|
||||
static gpg_error_t
|
||||
check_validity_period (ksba_isotime_t current_time,
|
||||
ksba_cert_t subject_cert,
|
||||
ksba_isotime_t exptime,
|
||||
int listmode, estream_t listfp, int depth)
|
||||
{
|
||||
gpg_error_t err;
|
||||
ksba_isotime_t not_before, not_after;
|
||||
|
||||
err = ksba_cert_get_validity (subject_cert, 0, not_before);
|
||||
if (!err)
|
||||
err = ksba_cert_get_validity (subject_cert, 1, not_after);
|
||||
if (err)
|
||||
{
|
||||
do_list (1, listmode, listfp,
|
||||
_("certificate with invalid validity: %s"), gpg_strerror (err));
|
||||
return gpg_error (GPG_ERR_BAD_CERT);
|
||||
}
|
||||
|
||||
if (*not_after)
|
||||
{
|
||||
if (!*exptime)
|
||||
gnupg_copy_time (exptime, not_after);
|
||||
else if (strcmp (not_after, exptime) < 0 )
|
||||
gnupg_copy_time (exptime, not_after);
|
||||
}
|
||||
|
||||
if (*not_before && strcmp (current_time, not_before) < 0 )
|
||||
{
|
||||
do_list (1, listmode, listfp,
|
||||
depth == 0 ? _("certificate not yet valid") :
|
||||
depth == -1 ? _("root certificate not yet valid") :
|
||||
/* other */ _("intermediate certificate not yet valid"));
|
||||
if (!listmode)
|
||||
{
|
||||
log_info (" (valid from ");
|
||||
gpgsm_dump_time (not_before);
|
||||
log_printf (")\n");
|
||||
}
|
||||
return gpg_error (GPG_ERR_CERT_TOO_YOUNG);
|
||||
}
|
||||
|
||||
if (*not_after && strcmp (current_time, not_after) > 0 )
|
||||
{
|
||||
do_list (opt.ignore_expiration?0:1, listmode, listfp,
|
||||
depth == 0 ? _("certificate has expired") :
|
||||
depth == -1 ? _("root certificate has expired") :
|
||||
/* other */ _("intermediate certificate has expired"));
|
||||
if (!listmode)
|
||||
{
|
||||
log_info (" (expired at ");
|
||||
gpgsm_dump_time (not_after);
|
||||
log_printf (")\n");
|
||||
}
|
||||
if (opt.ignore_expiration)
|
||||
log_info ("WARNING: ignoring expiration\n");
|
||||
else
|
||||
return gpg_error (GPG_ERR_CERT_EXPIRED);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is a variant of check_validity_period used with the chain
|
||||
model. The dextra contraint here is that notBefore and notAfter
|
||||
must exists and if the additional argument CHECK_TIME is given this
|
||||
time is used to check the validity period of SUBJECT_CERT. */
|
||||
static gpg_error_t
|
||||
check_validity_period_cm (ksba_isotime_t current_time,
|
||||
ksba_isotime_t check_time,
|
||||
ksba_cert_t subject_cert,
|
||||
ksba_isotime_t exptime,
|
||||
int listmode, estream_t listfp, int depth)
|
||||
{
|
||||
gpg_error_t err;
|
||||
ksba_isotime_t not_before, not_after;
|
||||
|
||||
err = ksba_cert_get_validity (subject_cert, 0, not_before);
|
||||
if (!err)
|
||||
err = ksba_cert_get_validity (subject_cert, 1, not_after);
|
||||
if (err)
|
||||
{
|
||||
do_list (1, listmode, listfp,
|
||||
_("certificate with invalid validity: %s"), gpg_strerror (err));
|
||||
return gpg_error (GPG_ERR_BAD_CERT);
|
||||
}
|
||||
if (!*not_before || !*not_after)
|
||||
{
|
||||
do_list (1, listmode, listfp,
|
||||
_("required certificate attributes missing: %s%s%s"),
|
||||
!*not_before? "notBefore":"",
|
||||
(!*not_before && !*not_after)? ", ":"",
|
||||
!*not_before? "notAfter":"");
|
||||
return gpg_error (GPG_ERR_BAD_CERT);
|
||||
}
|
||||
if (strcmp (not_before, not_after) > 0 )
|
||||
{
|
||||
do_list (1, listmode, listfp,
|
||||
_("certificate with invalid validity"));
|
||||
log_info (" (valid from ");
|
||||
gpgsm_dump_time (not_before);
|
||||
log_printf (" expired at ");
|
||||
gpgsm_dump_time (not_after);
|
||||
log_printf (")\n");
|
||||
return gpg_error (GPG_ERR_BAD_CERT);
|
||||
}
|
||||
|
||||
if (!*exptime)
|
||||
gnupg_copy_time (exptime, not_after);
|
||||
else if (strcmp (not_after, exptime) < 0 )
|
||||
gnupg_copy_time (exptime, not_after);
|
||||
|
||||
if (strcmp (current_time, not_before) < 0 )
|
||||
{
|
||||
do_list (1, listmode, listfp,
|
||||
depth == 0 ? _("certificate not yet valid") :
|
||||
depth == -1 ? _("root certificate not yet valid") :
|
||||
/* other */ _("intermediate certificate not yet valid"));
|
||||
if (!listmode)
|
||||
{
|
||||
log_info (" (valid from ");
|
||||
gpgsm_dump_time (not_before);
|
||||
log_printf (")\n");
|
||||
}
|
||||
return gpg_error (GPG_ERR_CERT_TOO_YOUNG);
|
||||
}
|
||||
|
||||
if (*check_time
|
||||
&& (strcmp (check_time, not_before) < 0
|
||||
|| strcmp (check_time, not_after) > 0))
|
||||
{
|
||||
/* Note that we don't need a case for the root certificate
|
||||
because its own consitency has already been checked. */
|
||||
do_list(opt.ignore_expiration?0:1, listmode, listfp,
|
||||
depth == 0 ?
|
||||
_("signature not created during lifetime of certificate") :
|
||||
depth == 1 ?
|
||||
_("certificate not created during lifetime of issuer") :
|
||||
_("intermediate certificate not created during lifetime "
|
||||
"of issuer"));
|
||||
if (!listmode)
|
||||
{
|
||||
log_info (depth== 0? _(" ( signature created at ") :
|
||||
/* */ _(" (certificate created at ") );
|
||||
gpgsm_dump_time (check_time);
|
||||
log_printf (")\n");
|
||||
log_info (depth==0? _(" (certificate valid from ") :
|
||||
/* */ _(" ( issuer valid from ") );
|
||||
gpgsm_dump_time (not_before);
|
||||
log_info (" to ");
|
||||
gpgsm_dump_time (not_after);
|
||||
log_printf (")\n");
|
||||
}
|
||||
if (opt.ignore_expiration)
|
||||
log_info ("WARNING: ignoring expiration\n");
|
||||
else
|
||||
return gpg_error (GPG_ERR_CERT_EXPIRED);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Ask the user whether he wants to mark the certificate CERT trusted.
|
||||
Returns true if the CERT is the trusted. We also check whether the
|
||||
agent is at all enabled to allow marktrusted and don't call it in
|
||||
this session again if it is not. */
|
||||
static int
|
||||
ask_marktrusted (ctrl_t ctrl, ksba_cert_t cert, int listmode)
|
||||
{
|
||||
static int no_more_questions;
|
||||
int rc;
|
||||
char *fpr;
|
||||
int success = 0;
|
||||
|
||||
fpr = gpgsm_get_fingerprint_string (cert, GCRY_MD_SHA1);
|
||||
log_info (_("fingerprint=%s\n"), fpr? fpr : "?");
|
||||
xfree (fpr);
|
||||
|
||||
if (no_more_questions)
|
||||
rc = gpg_error (GPG_ERR_NOT_SUPPORTED);
|
||||
else
|
||||
rc = gpgsm_agent_marktrusted (ctrl, cert);
|
||||
if (!rc)
|
||||
{
|
||||
log_info (_("root certificate has now been marked as trusted\n"));
|
||||
success = 1;
|
||||
}
|
||||
else if (!listmode)
|
||||
{
|
||||
gpgsm_dump_cert ("issuer", cert);
|
||||
log_info ("after checking the fingerprint, you may want "
|
||||
"to add it manually to the list of trusted certificates.\n");
|
||||
}
|
||||
|
||||
if (gpg_err_code (rc) == GPG_ERR_NOT_SUPPORTED)
|
||||
{
|
||||
if (!no_more_questions)
|
||||
log_info (_("interactive marking as trusted "
|
||||
"not enabled in gpg-agent\n"));
|
||||
no_more_questions = 1;
|
||||
}
|
||||
else if (gpg_err_code (rc) == GPG_ERR_CANCELED)
|
||||
{
|
||||
log_info (_("interactive marking as trusted "
|
||||
"disabled for this session\n"));
|
||||
no_more_questions = 1;
|
||||
}
|
||||
else
|
||||
set_already_asked_marktrusted (cert);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Validate a chain and optionally return the nearest expiration time
|
||||
in R_EXPTIME. With LISTMODE set to 1 a special listmode is
|
||||
activated where only information about the certificate is printed
|
||||
to FP and no output is send to the usual log stream.
|
||||
to LISTFP and no output is send to the usual log stream. If
|
||||
CHECKTIME_ARG is set, it is used only in the chain model instead of the
|
||||
current time.
|
||||
|
||||
Defined flag bits: 0 - do not do any dirmngr isvalid checks.
|
||||
Defined flag bits
|
||||
|
||||
VALIDATE_FLAG_NO_DIRMNGR - Do not do any dirmngr isvalid checks.
|
||||
VALIDATE_FLAG_CHAIN_MODEL - Check according to chain model.
|
||||
*/
|
||||
int
|
||||
gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
|
||||
int listmode, estream_t fp, unsigned int flags)
|
||||
static int
|
||||
do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
|
||||
ksba_isotime_t r_exptime,
|
||||
int listmode, estream_t listfp, unsigned int flags,
|
||||
struct rootca_flags_s *rootca_flags)
|
||||
{
|
||||
int rc = 0, depth = 0, maxdepth;
|
||||
int rc = 0, depth, maxdepth;
|
||||
char *issuer = NULL;
|
||||
char *subject = NULL;
|
||||
KEYDB_HANDLE kh = NULL;
|
||||
ksba_cert_t subject_cert = NULL, issuer_cert = NULL;
|
||||
ksba_isotime_t current_time;
|
||||
ksba_isotime_t check_time;
|
||||
ksba_isotime_t exptime;
|
||||
int any_expired = 0;
|
||||
int any_revoked = 0;
|
||||
@ -729,11 +1033,26 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
|
||||
int is_qualified = -1; /* Indicates whether the certificate stems
|
||||
from a qualified root certificate.
|
||||
-1 = unknown, 0 = no, 1 = yes. */
|
||||
int lm = listmode;
|
||||
chain_item_t chain = NULL; /* A list of all certificates in the chain. */
|
||||
|
||||
|
||||
gnupg_get_isotime (current_time);
|
||||
|
||||
if ( (flags & VALIDATE_FLAG_CHAIN_MODEL) )
|
||||
{
|
||||
if (!strcmp (checktime_arg, "19700101T000000"))
|
||||
{
|
||||
do_list (1, listmode, listfp,
|
||||
_("WARNING: creation time of signature not known - "
|
||||
"assuming current time"));
|
||||
gnupg_copy_time (check_time, current_time);
|
||||
}
|
||||
else
|
||||
gnupg_copy_time (check_time, checktime_arg);
|
||||
}
|
||||
else
|
||||
*check_time = 0;
|
||||
|
||||
if (r_exptime)
|
||||
*r_exptime = 0;
|
||||
*exptime = 0;
|
||||
@ -758,12 +1077,12 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
|
||||
subject_cert = cert;
|
||||
ksba_cert_ref (subject_cert);
|
||||
maxdepth = 50;
|
||||
depth = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int is_root;
|
||||
gpg_error_t istrusted_rc = -1;
|
||||
struct rootca_flags_s rootca_flags;
|
||||
|
||||
/* Put the certificate on our list. */
|
||||
{
|
||||
@ -788,13 +1107,16 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
|
||||
|
||||
if (!issuer)
|
||||
{
|
||||
do_list (1, lm, fp, _("no issuer found in certificate"));
|
||||
do_list (1, listmode, listfp, _("no issuer found in certificate"));
|
||||
rc = gpg_error (GPG_ERR_BAD_CERT);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
|
||||
/* Is this a self-issued certificate (i.e. the root certificate)? */
|
||||
/* Is this a self-issued certificate (i.e. the root
|
||||
certificate)? This is actually the same test as done by
|
||||
gpgsm_is_root_cert but here we want to keep the issuer and
|
||||
subject for later use. */
|
||||
is_root = (subject && !strcmp (issuer, subject));
|
||||
if (is_root)
|
||||
{
|
||||
@ -804,71 +1126,41 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
|
||||
check right here so that we can access special flags
|
||||
associated with that specific root certificate. */
|
||||
istrusted_rc = gpgsm_agent_istrusted (ctrl, subject_cert,
|
||||
&rootca_flags);
|
||||
rootca_flags);
|
||||
/* If the chain model extended attribute is used, make sure
|
||||
that our chain model flag is set. */
|
||||
if (has_validation_model_chain (subject_cert, listmode, listfp))
|
||||
rootca_flags->chain_model = 1;
|
||||
}
|
||||
|
||||
|
||||
/* Check the validity period. */
|
||||
{
|
||||
ksba_isotime_t not_before, not_after;
|
||||
|
||||
rc = ksba_cert_get_validity (subject_cert, 0, not_before);
|
||||
if (!rc)
|
||||
rc = ksba_cert_get_validity (subject_cert, 1, not_after);
|
||||
if (rc)
|
||||
{
|
||||
do_list (1, lm, fp, _("certificate with invalid validity: %s"),
|
||||
gpg_strerror (rc));
|
||||
rc = gpg_error (GPG_ERR_BAD_CERT);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (*not_after)
|
||||
{
|
||||
if (!*exptime)
|
||||
gnupg_copy_time (exptime, not_after);
|
||||
else if (strcmp (not_after, exptime) < 0 )
|
||||
gnupg_copy_time (exptime, not_after);
|
||||
}
|
||||
|
||||
if (*not_before && strcmp (current_time, not_before) < 0 )
|
||||
{
|
||||
do_list (1, lm, fp, _("certificate not yet valid"));
|
||||
if (!lm)
|
||||
{
|
||||
log_info ("(valid from ");
|
||||
gpgsm_dump_time (not_before);
|
||||
log_printf (")\n");
|
||||
}
|
||||
rc = gpg_error (GPG_ERR_CERT_TOO_YOUNG);
|
||||
goto leave;
|
||||
}
|
||||
if (*not_after && strcmp (current_time, not_after) > 0 )
|
||||
{
|
||||
do_list (opt.ignore_expiration?0:1, lm, fp,
|
||||
_("certificate has expired"));
|
||||
if (!lm)
|
||||
{
|
||||
log_info ("(expired at ");
|
||||
gpgsm_dump_time (not_after);
|
||||
log_printf (")\n");
|
||||
}
|
||||
if (opt.ignore_expiration)
|
||||
log_info ("WARNING: ignoring expiration\n");
|
||||
else
|
||||
any_expired = 1;
|
||||
}
|
||||
}
|
||||
if ( (flags & VALIDATE_FLAG_CHAIN_MODEL) )
|
||||
rc = check_validity_period_cm (current_time, check_time, subject_cert,
|
||||
exptime, listmode, listfp,
|
||||
(depth && is_root)? -1: depth);
|
||||
else
|
||||
rc = check_validity_period (current_time, subject_cert,
|
||||
exptime, listmode, listfp,
|
||||
(depth && is_root)? -1: depth);
|
||||
if (gpg_err_code (rc) == GPG_ERR_CERT_EXPIRED)
|
||||
{
|
||||
any_expired = 1;
|
||||
rc = 0;
|
||||
}
|
||||
else if (rc)
|
||||
goto leave;
|
||||
|
||||
|
||||
/* Assert that we understand all critical extensions. */
|
||||
rc = unknown_criticals (subject_cert, listmode, fp);
|
||||
rc = unknown_criticals (subject_cert, listmode, listfp);
|
||||
if (rc)
|
||||
goto leave;
|
||||
|
||||
/* Do a policy check. */
|
||||
if (!opt.no_policy_check)
|
||||
{
|
||||
rc = check_cert_policy (subject_cert, listmode, fp);
|
||||
rc = check_cert_policy (subject_cert, listmode, listfp);
|
||||
if (gpg_err_code (rc) == GPG_ERR_NO_POLICY_MATCH)
|
||||
{
|
||||
any_no_policy_match = 1;
|
||||
@ -879,7 +1171,7 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
|
||||
}
|
||||
|
||||
|
||||
/* Is this a self-issued certificate? */
|
||||
/* If this is the root certificate we are at the end of the chain. */
|
||||
if (is_root)
|
||||
{
|
||||
if (!istrusted_rc)
|
||||
@ -888,7 +1180,7 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
|
||||
{
|
||||
/* We only check the signature if the certificate is not
|
||||
trusted for better diagnostics. */
|
||||
do_list (1, lm, fp,
|
||||
do_list (1, listmode, listfp,
|
||||
_("self-signed certificate has a BAD signature"));
|
||||
if (DBG_X509)
|
||||
{
|
||||
@ -898,9 +1190,9 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
|
||||
: GPG_ERR_BAD_CERT);
|
||||
goto leave;
|
||||
}
|
||||
if (!rootca_flags.relax)
|
||||
if (!rootca_flags->relax)
|
||||
{
|
||||
rc = allowed_ca (subject_cert, NULL, listmode, fp);
|
||||
rc = allowed_ca (subject_cert, NULL, listmode, listfp);
|
||||
if (rc)
|
||||
goto leave;
|
||||
}
|
||||
@ -957,57 +1249,17 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
|
||||
;
|
||||
else if (gpg_err_code (rc) == GPG_ERR_NOT_TRUSTED)
|
||||
{
|
||||
do_list (0, lm, fp, _("root certificate is not marked trusted"));
|
||||
do_list (0, listmode, listfp,
|
||||
_("root certificate is not marked trusted"));
|
||||
/* If we already figured out that the certificate is
|
||||
expired it does not make much sense to ask the user
|
||||
whether we wants to trust the root certificate. He
|
||||
whether we wants to trust the root certificate. We
|
||||
should do this only if the certificate under question
|
||||
will then be usable. We also check whether the agent
|
||||
is at all enabled to allo marktrusted and don't call
|
||||
it in this session again if it is not. */
|
||||
will then be usable. */
|
||||
if ( !any_expired
|
||||
&& (!lm || !already_asked_marktrusted (subject_cert)))
|
||||
{
|
||||
static int no_more_questions; /* during this session. */
|
||||
int rc2;
|
||||
char *fpr = gpgsm_get_fingerprint_string (subject_cert,
|
||||
GCRY_MD_SHA1);
|
||||
log_info (_("fingerprint=%s\n"), fpr? fpr : "?");
|
||||
xfree (fpr);
|
||||
if (no_more_questions)
|
||||
rc2 = gpg_error (GPG_ERR_NOT_SUPPORTED);
|
||||
else
|
||||
rc2 = gpgsm_agent_marktrusted (ctrl, subject_cert);
|
||||
if (!rc2)
|
||||
{
|
||||
log_info (_("root certificate has now"
|
||||
" been marked as trusted\n"));
|
||||
rc = 0;
|
||||
}
|
||||
else if (!lm)
|
||||
{
|
||||
gpgsm_dump_cert ("issuer", subject_cert);
|
||||
log_info ("after checking the fingerprint, you may want "
|
||||
"to add it manually to the list of trusted "
|
||||
"certificates.\n");
|
||||
}
|
||||
|
||||
if (gpg_err_code (rc2) == GPG_ERR_NOT_SUPPORTED)
|
||||
{
|
||||
if (!no_more_questions)
|
||||
log_info (_("interactive marking as trusted "
|
||||
"not enabled in gpg-agent\n"));
|
||||
no_more_questions = 1;
|
||||
}
|
||||
else if (gpg_err_code (rc2) == GPG_ERR_CANCELED)
|
||||
{
|
||||
log_info (_("interactive marking as trusted "
|
||||
"disabled for this session\n"));
|
||||
no_more_questions = 1;
|
||||
}
|
||||
else
|
||||
set_already_asked_marktrusted (subject_cert);
|
||||
}
|
||||
&& (!listmode || !already_asked_marktrusted (subject_cert))
|
||||
&& ask_marktrusted (ctrl, subject_cert, listmode) )
|
||||
rc = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1019,12 +1271,14 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
|
||||
goto leave;
|
||||
|
||||
/* Check for revocations etc. */
|
||||
if ((flags & 1))
|
||||
if ((flags & VALIDATE_FLAG_NO_DIRMNGR))
|
||||
;
|
||||
else if (opt.no_trusted_cert_crl_check || rootca_flags.relax)
|
||||
else if (opt.no_trusted_cert_crl_check || rootca_flags->relax)
|
||||
;
|
||||
else
|
||||
rc = is_cert_still_valid (ctrl, lm, fp,
|
||||
rc = is_cert_still_valid (ctrl,
|
||||
(flags & VALIDATE_FLAG_CHAIN_MODEL),
|
||||
listmode, listfp,
|
||||
subject_cert, subject_cert,
|
||||
&any_revoked, &any_no_crl,
|
||||
&any_crl_too_old);
|
||||
@ -1032,13 +1286,13 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
|
||||
goto leave;
|
||||
|
||||
break; /* Okay: a self-signed certicate is an end-point. */
|
||||
}
|
||||
} /* End is_root. */
|
||||
|
||||
|
||||
/* Take care that the chain does not get too long. */
|
||||
depth++;
|
||||
if (depth > maxdepth)
|
||||
if ((depth+1) > maxdepth)
|
||||
{
|
||||
do_list (1, lm, fp, _("certificate chain too long\n"));
|
||||
do_list (1, listmode, listfp, _("certificate chain too long\n"));
|
||||
rc = gpg_error (GPG_ERR_BAD_CERT_CHAIN);
|
||||
goto leave;
|
||||
}
|
||||
@ -1050,8 +1304,8 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
|
||||
{
|
||||
if (rc == -1)
|
||||
{
|
||||
do_list (0, lm, fp, _("issuer certificate not found"));
|
||||
if (!lm)
|
||||
do_list (0, listmode, listfp, _("issuer certificate not found"));
|
||||
if (!listmode)
|
||||
{
|
||||
log_info ("issuer certificate: #/");
|
||||
gpgsm_dump_string (issuer);
|
||||
@ -1083,7 +1337,7 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
|
||||
rc = gpgsm_check_cert_sig (issuer_cert, subject_cert);
|
||||
if (rc)
|
||||
{
|
||||
do_list (0, lm, fp, _("certificate has a BAD signature"));
|
||||
do_list (0, listmode, listfp, _("certificate has a BAD signature"));
|
||||
if (DBG_X509)
|
||||
{
|
||||
gpgsm_dump_cert ("signing issuer", issuer_cert);
|
||||
@ -1113,8 +1367,9 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
|
||||
}
|
||||
else
|
||||
{
|
||||
do_list (0, lm, fp, _("found another possible matching "
|
||||
"CA certificate - trying again"));
|
||||
do_list (0, listmode, listfp,
|
||||
_("found another possible matching "
|
||||
"CA certificate - trying again"));
|
||||
ksba_cert_release (issuer_cert);
|
||||
issuer_cert = tmp_cert;
|
||||
goto try_another_cert;
|
||||
@ -1128,14 +1383,15 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
|
||||
goto leave;
|
||||
}
|
||||
|
||||
is_root = 0;
|
||||
is_root = gpgsm_is_root_cert (issuer_cert);
|
||||
istrusted_rc = -1;
|
||||
|
||||
|
||||
/* Check that a CA is allowed to issue certificates. */
|
||||
{
|
||||
int chainlen;
|
||||
|
||||
rc = allowed_ca (issuer_cert, &chainlen, listmode, fp);
|
||||
rc = allowed_ca (issuer_cert, &chainlen, listmode, listfp);
|
||||
if (rc)
|
||||
{
|
||||
/* Not allowed. Check whether this is a trusted root
|
||||
@ -1146,12 +1402,11 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
|
||||
certificates carry proper BasicContraints our way of
|
||||
overriding an error in the way is justified for
|
||||
performance reasons. */
|
||||
if (gpgsm_is_root_cert (issuer_cert))
|
||||
if (is_root)
|
||||
{
|
||||
is_root = 1;
|
||||
istrusted_rc = gpgsm_agent_istrusted (ctrl, issuer_cert,
|
||||
&rootca_flags);
|
||||
if (!istrusted_rc && rootca_flags.relax)
|
||||
rootca_flags);
|
||||
if (!istrusted_rc && rootca_flags->relax)
|
||||
{
|
||||
/* Ignore the error due to the relax flag. */
|
||||
rc = 0;
|
||||
@ -1161,9 +1416,9 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
|
||||
}
|
||||
if (rc)
|
||||
goto leave;
|
||||
if (chainlen >= 0 && (depth - 1) > chainlen)
|
||||
if (chainlen >= 0 && depth > chainlen)
|
||||
{
|
||||
do_list (1, lm, fp,
|
||||
do_list (1, listmode, listfp,
|
||||
_("certificate chain longer than allowed by CA (%d)"),
|
||||
chainlen);
|
||||
rc = gpg_error (GPG_ERR_BAD_CERT_CHAIN);
|
||||
@ -1188,13 +1443,15 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
|
||||
/* Check for revocations etc. Note that for a root certificate
|
||||
this test is done a second time later. This should eventually
|
||||
be fixed. */
|
||||
if ((flags & 1))
|
||||
if ((flags & VALIDATE_FLAG_NO_DIRMNGR))
|
||||
rc = 0;
|
||||
else if (is_root && (opt.no_trusted_cert_crl_check
|
||||
|| (!istrusted_rc && rootca_flags.relax)))
|
||||
;
|
||||
|| (!istrusted_rc && rootca_flags->relax)))
|
||||
rc = 0;
|
||||
else
|
||||
rc = is_cert_still_valid (ctrl, lm, fp,
|
||||
rc = is_cert_still_valid (ctrl,
|
||||
(flags & VALIDATE_FLAG_CHAIN_MODEL),
|
||||
listmode, listfp,
|
||||
subject_cert, issuer_cert,
|
||||
&any_revoked, &any_no_crl, &any_crl_too_old);
|
||||
if (rc)
|
||||
@ -1202,13 +1459,29 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
|
||||
|
||||
|
||||
if (opt.verbose && !listmode)
|
||||
log_info ("certificate is good\n");
|
||||
log_info (depth == 0 ? _("certificate is good\n") :
|
||||
!is_root ? _("intermediate certificate is good\n") :
|
||||
/* other */ _("root certificate is good\n"));
|
||||
|
||||
/* Under the chain model the next check time is the creation
|
||||
time of the subject certificate. */
|
||||
if ( (flags & VALIDATE_FLAG_CHAIN_MODEL) )
|
||||
{
|
||||
rc = ksba_cert_get_validity (subject_cert, 0, check_time);
|
||||
if (rc)
|
||||
{
|
||||
/* That will never happen as we have already checked
|
||||
this above. */
|
||||
BUG ();
|
||||
}
|
||||
}
|
||||
|
||||
/* For the next round the current issuer becomes the new subject. */
|
||||
keydb_search_reset (kh);
|
||||
ksba_cert_release (subject_cert);
|
||||
subject_cert = issuer_cert;
|
||||
issuer_cert = NULL;
|
||||
depth++;
|
||||
} /* End chain traversal. */
|
||||
|
||||
if (!listmode)
|
||||
@ -1238,7 +1511,7 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
|
||||
|
||||
leave:
|
||||
/* If we have traversed a complete chain up to the root we will
|
||||
reset the ephemeral flag for all these certificates. his is done
|
||||
reset the ephemeral flag for all these certificates. This is done
|
||||
regardless of any error because those errors may only be
|
||||
transient. */
|
||||
if (chain && chain->is_root)
|
||||
@ -1306,6 +1579,61 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
|
||||
}
|
||||
|
||||
|
||||
/* Validate a certifcate chain. For a description see the
|
||||
do_validate_chain. This function is a wrapper to handle a root
|
||||
certificate with the chain_model flag set. If RETFLAGS is not
|
||||
NULL, flags indicating now the verification was done are stored
|
||||
there. The only defined flag for RETFLAGS is
|
||||
VALIDATE_FLAG_CHAIN_MODEL.
|
||||
|
||||
If you are verifying a signature you should set CHECKTIME to the
|
||||
creation time of the signature. If your are verifying a
|
||||
certificate, set it nil (i.e. the empty string). If the creation
|
||||
date of the signature is not known use the special date
|
||||
"19700101T000000" which is treated in a special way here. */
|
||||
int
|
||||
gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime,
|
||||
ksba_isotime_t r_exptime,
|
||||
int listmode, estream_t listfp, unsigned int flags,
|
||||
unsigned int *retflags)
|
||||
{
|
||||
int rc;
|
||||
struct rootca_flags_s rootca_flags;
|
||||
unsigned int dummy_retflags;
|
||||
|
||||
if (!retflags)
|
||||
retflags = &dummy_retflags;
|
||||
|
||||
if (ctrl->validation_model == 1)
|
||||
flags |= VALIDATE_FLAG_CHAIN_MODEL;
|
||||
|
||||
*retflags = (flags & VALIDATE_FLAG_CHAIN_MODEL);
|
||||
memset (&rootca_flags, 0, sizeof rootca_flags);
|
||||
|
||||
rc = do_validate_chain (ctrl, cert, checktime,
|
||||
r_exptime, listmode, listfp, flags,
|
||||
&rootca_flags);
|
||||
if (gpg_err_code (rc) == GPG_ERR_CERT_EXPIRED
|
||||
&& !(flags & VALIDATE_FLAG_CHAIN_MODEL)
|
||||
&& (rootca_flags.valid && rootca_flags.chain_model))
|
||||
{
|
||||
do_list (0, listmode, listfp, _("switching to chain model"));
|
||||
rc = do_validate_chain (ctrl, cert, checktime,
|
||||
r_exptime, listmode, listfp,
|
||||
(flags |= VALIDATE_FLAG_CHAIN_MODEL),
|
||||
&rootca_flags);
|
||||
*retflags |= VALIDATE_FLAG_CHAIN_MODEL;
|
||||
}
|
||||
|
||||
if (opt.verbose)
|
||||
do_list (0, listmode, listfp, _("validation model used: %s"),
|
||||
(*retflags & VALIDATE_FLAG_CHAIN_MODEL)?
|
||||
_("chain model"):_("shell model"));
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* Check that the given certificate is valid but DO NOT check any
|
||||
constraints. We assume that the issuers certificate is already in
|
||||
the DB and that this one is valid; which it should be because it
|
||||
@ -1399,7 +1727,7 @@ gpgsm_basic_cert_check (ksba_cert_t cert)
|
||||
goto leave;
|
||||
}
|
||||
if (opt.verbose)
|
||||
log_info ("certificate is good\n");
|
||||
log_info (_("certificate is good\n"));
|
||||
}
|
||||
|
||||
leave:
|
||||
|
@ -343,13 +343,17 @@ gpgsm_check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert)
|
||||
|
||||
int
|
||||
gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval,
|
||||
gcry_md_hd_t md, int algo)
|
||||
gcry_md_hd_t md, int mdalgo, int *r_pkalgo)
|
||||
{
|
||||
int rc;
|
||||
ksba_sexp_t p;
|
||||
gcry_mpi_t frame;
|
||||
gcry_sexp_t s_sig, s_hash, s_pkey;
|
||||
size_t n;
|
||||
int pkalgo;
|
||||
|
||||
if (r_pkalgo)
|
||||
*r_pkalgo = 0;
|
||||
|
||||
n = gcry_sexp_canon_len (sigval, 0, NULL, NULL);
|
||||
if (!n)
|
||||
@ -385,8 +389,10 @@ gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval,
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
rc = do_encode_md (md, algo, pk_algo_from_sexp (s_pkey),
|
||||
pkalgo = pk_algo_from_sexp (s_pkey);
|
||||
if (r_pkalgo)
|
||||
*r_pkalgo = pkalgo;
|
||||
rc = do_encode_md (md, mdalgo, pkalgo,
|
||||
gcry_pk_get_nbits (s_pkey), s_pkey, &frame);
|
||||
if (rc)
|
||||
{
|
||||
|
@ -71,10 +71,10 @@ gpgsm_print_serial (estream_t fp, ksba_const_sexp_t sn)
|
||||
p++;
|
||||
n = strtoul (p, &endp, 10);
|
||||
p = endp;
|
||||
if (*p!=':')
|
||||
if (*p++ != ':')
|
||||
es_fputs ("[Internal Error - invalid S-expression]", fp);
|
||||
else
|
||||
es_write_hexstring (fp, p, strlen (p), 0, NULL);
|
||||
es_write_hexstring (fp, p, n, 0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -936,7 +936,7 @@ gpgsm_format_keydesc (ksba_cert_t cert)
|
||||
_("Please enter the passphrase to unlock the"
|
||||
" secret key for:\n"
|
||||
"\"%s\"\n"
|
||||
"S/N %s, ID %08lX, created %s" ),
|
||||
"S/N %s, ID 0x%08lX, created %s" ),
|
||||
subject? subject:"?",
|
||||
sn? sn: "?",
|
||||
gpgsm_get_short_fingerprint (cert),
|
||||
|
@ -374,7 +374,8 @@ gpgsm_add_to_certlist (ctrl_t ctrl, const char *name, int secret,
|
||||
}
|
||||
}
|
||||
if (!rc)
|
||||
rc = gpgsm_validate_chain (ctrl, cert, NULL, 0, NULL, 0);
|
||||
rc = gpgsm_validate_chain (ctrl, cert, "", NULL,
|
||||
0, NULL, 0, NULL);
|
||||
if (!rc)
|
||||
{
|
||||
certlist_t cl = xtrycalloc (1, sizeof *cl);
|
||||
|
49
sm/gpgsm.c
49
sm/gpgsm.c
@ -195,6 +195,7 @@ enum cmd_and_opt_values {
|
||||
oSetFilename,
|
||||
oSetPolicyURL,
|
||||
oUseEmbeddedFilename,
|
||||
oValidationModel,
|
||||
oComment,
|
||||
oDefaultComment,
|
||||
oThrowKeyid,
|
||||
@ -302,6 +303,8 @@ static ARGPARSE_OPTS opts[] = {
|
||||
{ oDisableOCSP, "disable-ocsp", 0, "@" },
|
||||
{ oEnableOCSP, "enable-ocsp", 0, N_("check validity using OCSP")},
|
||||
|
||||
{ oValidationModel, "validation-model", 2, "@"},
|
||||
|
||||
{ oIncludeCerts, "include-certs", 1,
|
||||
N_("|N|number of certificates to include") },
|
||||
|
||||
@ -423,7 +426,7 @@ static ARGPARSE_OPTS opts[] = {
|
||||
{ oLCmessages, "lc-messages", 2, "@" },
|
||||
{ oDirmngrProgram, "dirmngr-program", 2 , "@" },
|
||||
{ oProtectToolProgram, "protect-tool-program", 2 , "@" },
|
||||
{ oFakedSystemTime, "faked-system-time", 4, "@" }, /* (epoch time) */
|
||||
{ oFakedSystemTime, "faked-system-time", 2, "@" }, /* (epoch time) */
|
||||
|
||||
|
||||
{ oNoBatch, "no-batch", 0, "@" },
|
||||
@ -472,6 +475,8 @@ static int allow_special_filenames;
|
||||
/* Default value for include-certs. */
|
||||
static int default_include_certs = 1; /* Only include the signer's cert. */
|
||||
|
||||
/* Whether the chain mode shall be used for validation. */
|
||||
static int default_validation_model;
|
||||
|
||||
|
||||
static char *build_list (const char *text,
|
||||
@ -700,6 +705,17 @@ do_add_recipient (ctrl_t ctrl, const char *name,
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
parse_validation_model (const char *model)
|
||||
{
|
||||
int i = gpgsm_parse_validation_model (model);
|
||||
if (i == -1)
|
||||
log_error (_("unknown validation model `%s'\n"), model);
|
||||
else
|
||||
default_validation_model = i;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main ( int argc, char **argv)
|
||||
{
|
||||
@ -772,9 +788,6 @@ main ( int argc, char **argv)
|
||||
opt.def_cipher_algoid = "3DES"; /*des-EDE3-CBC*/
|
||||
|
||||
opt.homedir = default_homedir ();
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
opt.no_crl_check = 1;
|
||||
#endif
|
||||
|
||||
/* First check whether we have a config file on the commandline */
|
||||
orig_argc = argc;
|
||||
@ -1095,7 +1108,12 @@ main ( int argc, char **argv)
|
||||
break;
|
||||
|
||||
case oFakedSystemTime:
|
||||
gnupg_set_time ( (time_t)pargs.r.ret_ulong, 0);
|
||||
{
|
||||
time_t faked_time = isotime2epoch (pargs.r.ret_str);
|
||||
if (faked_time == (time_t)(-1))
|
||||
faked_time = (time_t)strtoul (pargs.r.ret_str, NULL, 10);
|
||||
gnupg_set_time (faked_time, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case oNoDefKeyring: default_keyring = 0; break;
|
||||
@ -1174,7 +1192,8 @@ main ( int argc, char **argv)
|
||||
case oNoRandomSeedFile: use_random_seed = 0; break;
|
||||
|
||||
case oEnableSpecialFilenames: allow_special_filenames =1; break;
|
||||
|
||||
|
||||
case oValidationModel: parse_validation_model (pargs.r.ret_str); break;
|
||||
|
||||
case aDummy:
|
||||
break;
|
||||
@ -1201,7 +1220,11 @@ main ( int argc, char **argv)
|
||||
|
||||
if (log_get_errorcount(0))
|
||||
gpgsm_exit(2);
|
||||
|
||||
|
||||
/* Now that we have the optiosn parsed we need to update the default
|
||||
control structure. */
|
||||
gpgsm_init_default_ctrl (&ctrl);
|
||||
|
||||
if (nogreeting)
|
||||
greeting = 0;
|
||||
|
||||
@ -1715,9 +1738,21 @@ gpgsm_init_default_ctrl (struct server_control_s *ctrl)
|
||||
{
|
||||
ctrl->include_certs = default_include_certs;
|
||||
ctrl->use_ocsp = opt.enable_ocsp;
|
||||
ctrl->validation_model = default_validation_model;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
gpgsm_parse_validation_model (const char *model)
|
||||
{
|
||||
if (!ascii_strcasecmp (model, "shell") )
|
||||
return 0;
|
||||
else if ( !ascii_strcasecmp (model, "chain") )
|
||||
return 1;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* Check whether the filename has the form "-&nnnn", where n is a
|
||||
non-zero number. Returns this number or -1 if it is not the case. */
|
||||
|
17
sm/gpgsm.h
17
sm/gpgsm.h
@ -164,6 +164,7 @@ struct server_control_s
|
||||
certificates up the chain (0 = none, 1 = only
|
||||
signer) */
|
||||
int use_ocsp; /* Set to true if OCSP should be used. */
|
||||
int validation_model; /* Set to 1 for the chain model. */
|
||||
};
|
||||
|
||||
|
||||
@ -185,8 +186,10 @@ typedef struct certlist_s *certlist_t;
|
||||
/* A structure carrying information about trusted root certificates. */
|
||||
struct rootca_flags_s
|
||||
{
|
||||
unsigned int valid:1; /* The rest of the structure has valid
|
||||
information. */
|
||||
unsigned int relax:1; /* Relax checking of root certificates. */
|
||||
|
||||
unsigned int chain_model:1; /* Root requires the use of the chain model. */
|
||||
};
|
||||
|
||||
|
||||
@ -194,6 +197,7 @@ struct rootca_flags_s
|
||||
/*-- gpgsm.c --*/
|
||||
void gpgsm_exit (int rc);
|
||||
void gpgsm_init_default_ctrl (struct server_control_s *ctrl);
|
||||
int gpgsm_parse_validation_model (const char *model);
|
||||
|
||||
/*-- server.c --*/
|
||||
void gpgsm_server (certlist_t default_recplist);
|
||||
@ -253,7 +257,7 @@ char *gpgsm_format_keydesc (ksba_cert_t cert);
|
||||
/*-- certcheck.c --*/
|
||||
int gpgsm_check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert);
|
||||
int gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval,
|
||||
gcry_md_hd_t md, int hash_algo);
|
||||
gcry_md_hd_t md, int hash_algo, int *r_pkalgo);
|
||||
/* fixme: move create functions to another file */
|
||||
int gpgsm_create_cms_signature (ctrl_t ctrl,
|
||||
ksba_cert_t cert, gcry_md_hd_t md, int mdalgo,
|
||||
@ -261,12 +265,19 @@ int gpgsm_create_cms_signature (ctrl_t ctrl,
|
||||
|
||||
|
||||
/*-- certchain.c --*/
|
||||
|
||||
/* Flags used with gpgsm_validate_chain. */
|
||||
#define VALIDATE_FLAG_NO_DIRMNGR 1
|
||||
#define VALIDATE_FLAG_CHAIN_MODEL 2
|
||||
|
||||
|
||||
int gpgsm_walk_cert_chain (ksba_cert_t start, ksba_cert_t *r_next);
|
||||
int gpgsm_is_root_cert (ksba_cert_t cert);
|
||||
int gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert,
|
||||
ksba_isotime_t checktime,
|
||||
ksba_isotime_t r_exptime,
|
||||
int listmode, estream_t listfp,
|
||||
unsigned int flags);
|
||||
unsigned int flags, unsigned int *retflags);
|
||||
int gpgsm_basic_cert_check (ksba_cert_t cert);
|
||||
|
||||
/*-- certlist.c --*/
|
||||
|
@ -173,7 +173,7 @@ check_and_store (ctrl_t ctrl, struct stats_s *stats,
|
||||
*/
|
||||
rc = gpgsm_basic_cert_check (cert);
|
||||
if (!rc && ctrl->with_validation)
|
||||
rc = gpgsm_validate_chain (ctrl, cert, NULL, 0, NULL, 0);
|
||||
rc = gpgsm_validate_chain (ctrl, cert, "", NULL, 0, NULL, 0, NULL);
|
||||
if (!rc || (!ctrl->with_validation
|
||||
&& gpg_err_code (rc) == GPG_ERR_MISSING_CERT) )
|
||||
{
|
||||
|
36
sm/keylist.c
36
sm/keylist.c
@ -176,6 +176,9 @@ static struct
|
||||
/* GnuPG extensions */
|
||||
{ "1.3.6.1.4.1.11591.2.1.1", "pkaAddress" },
|
||||
|
||||
/* Extensions used by the Bundesnetzagentur. */
|
||||
{ "1.3.6.1.4.1.8301.3.5", "validityModel" },
|
||||
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@ -345,9 +348,10 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
|
||||
const char *chain_id;
|
||||
char *chain_id_buffer = NULL;
|
||||
int is_root = 0;
|
||||
char *kludge_uid;
|
||||
|
||||
if (ctrl->with_validation)
|
||||
valerr = gpgsm_validate_chain (ctrl, cert, NULL, 1, NULL, 0);
|
||||
valerr = gpgsm_validate_chain (ctrl, cert, "", NULL, 1, NULL, 0, NULL);
|
||||
else
|
||||
valerr = 0;
|
||||
|
||||
@ -484,8 +488,15 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
|
||||
print_key_data (cert, fp);
|
||||
}
|
||||
|
||||
kludge_uid = NULL;
|
||||
for (idx=0; (p = ksba_cert_get_subject (cert,idx)); idx++)
|
||||
{
|
||||
/* In the case that the same email address is in the subecj DN
|
||||
as weel as in an alternate subject name we avoid printing it
|
||||
a second time. */
|
||||
if (kludge_uid && !strcmp (kludge_uid, p))
|
||||
continue;
|
||||
|
||||
es_fprintf (fp, "uid:%s::::::::", truststring);
|
||||
es_write_sanitized (fp, p, strlen (p), ":", NULL);
|
||||
es_putc (':', fp);
|
||||
@ -497,19 +508,20 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
|
||||
the keydb. But as long as we don't have a way to pass
|
||||
the meta data back, we just check it the same way as the
|
||||
code used to create the keybox meta data does */
|
||||
char *pp = email_kludge (p);
|
||||
if (pp)
|
||||
kludge_uid = email_kludge (p);
|
||||
if (kludge_uid)
|
||||
{
|
||||
es_fprintf (fp, "uid:%s::::::::", truststring);
|
||||
es_write_sanitized (fp, pp, strlen (pp), ":", NULL);
|
||||
es_write_sanitized (fp, kludge_uid, strlen (kludge_uid),
|
||||
":", NULL);
|
||||
es_putc (':', fp);
|
||||
es_putc (':', fp);
|
||||
es_putc ('\n', fp);
|
||||
xfree (pp);
|
||||
}
|
||||
}
|
||||
xfree (p);
|
||||
}
|
||||
xfree (kludge_uid);
|
||||
}
|
||||
|
||||
|
||||
@ -570,8 +582,11 @@ list_cert_raw (ctrl_t ctrl, KEYDB_HANDLE hd,
|
||||
ksba_name_t name, name2;
|
||||
unsigned int reason;
|
||||
|
||||
es_fprintf (fp, " ID: 0x%08lX\n",
|
||||
gpgsm_get_short_fingerprint (cert));
|
||||
|
||||
sexp = ksba_cert_get_serial (cert);
|
||||
es_fputs ("Serial number: ", fp);
|
||||
es_fputs (" S/N: ", fp);
|
||||
gpgsm_print_serial (fp, sexp);
|
||||
ksba_free (sexp);
|
||||
es_putc ('\n', fp);
|
||||
@ -887,7 +902,7 @@ list_cert_raw (ctrl_t ctrl, KEYDB_HANDLE hd,
|
||||
|
||||
if (with_validation)
|
||||
{
|
||||
err = gpgsm_validate_chain (ctrl, cert, NULL, 1, fp, 0);
|
||||
err = gpgsm_validate_chain (ctrl, cert, "", NULL, 1, fp, 0, NULL);
|
||||
if (!err)
|
||||
es_fprintf (fp, " [certificate is good]\n");
|
||||
else
|
||||
@ -924,8 +939,11 @@ list_cert_std (ctrl_t ctrl, ksba_cert_t cert, estream_t fp, int have_secret,
|
||||
unsigned int kusage;
|
||||
char *string, *p, *pend;
|
||||
|
||||
es_fprintf (fp, " ID: 0x%08lX\n",
|
||||
gpgsm_get_short_fingerprint (cert));
|
||||
|
||||
sexp = ksba_cert_get_serial (cert);
|
||||
es_fputs ("Serial number: ", fp);
|
||||
es_fputs (" S/N: ", fp);
|
||||
gpgsm_print_serial (fp, sexp);
|
||||
ksba_free (sexp);
|
||||
es_putc ('\n', fp);
|
||||
@ -1088,7 +1106,7 @@ list_cert_std (ctrl_t ctrl, ksba_cert_t cert, estream_t fp, int have_secret,
|
||||
size_t buflen;
|
||||
char buffer[1];
|
||||
|
||||
err = gpgsm_validate_chain (ctrl, cert, NULL, 1, fp, 0);
|
||||
err = gpgsm_validate_chain (ctrl, cert, "", NULL, 1, fp, 0, NULL);
|
||||
tmperr = ksba_cert_get_user_data (cert, "is_qualified",
|
||||
&buffer, sizeof (buffer), &buflen);
|
||||
if (!tmperr && buflen)
|
||||
|
@ -244,6 +244,14 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
|
||||
int i = *value? atoi (value) : 0;
|
||||
ctrl->with_validation = i;
|
||||
}
|
||||
else if (!strcmp (key, "validation-model"))
|
||||
{
|
||||
int i = gpgsm_parse_validation_model (value);
|
||||
if ( i >= 0 && i <= 1 )
|
||||
ctrl->validation_model = i;
|
||||
else
|
||||
return gpg_error (GPG_ERR_ASS_PARAMETER);
|
||||
}
|
||||
else if (!strcmp (key, "with-key-data"))
|
||||
{
|
||||
opt.with_key_data = 1;
|
||||
|
@ -380,7 +380,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
||||
check that the signer's certificate is usable and valid. */
|
||||
rc = gpgsm_cert_use_sign_p (cert);
|
||||
if (!rc)
|
||||
rc = gpgsm_validate_chain (ctrl, cert, NULL, 0, NULL, 0);
|
||||
rc = gpgsm_validate_chain (ctrl, cert, "", NULL, 0, NULL, 0, NULL);
|
||||
if (rc)
|
||||
goto leave;
|
||||
|
||||
|
52
sm/verify.c
52
sm/verify.c
@ -1,5 +1,5 @@
|
||||
/* verify.c - Verify a messages signature
|
||||
* Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2001, 2002, 2003, 2007 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -246,6 +246,8 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, FILE *out_fp)
|
||||
char *msgdigest = NULL;
|
||||
size_t msgdigestlen;
|
||||
char *ctattr;
|
||||
int info_pkalgo;
|
||||
unsigned int verifyflags;
|
||||
|
||||
rc = ksba_cms_get_issuer_serial (cms, signer, &issuer, &serial);
|
||||
if (!signer && gpg_err_code (rc) == GPG_ERR_NO_DATA
|
||||
@ -388,7 +390,7 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, FILE *out_fp)
|
||||
gpgsm_dump_time (sigtime);
|
||||
else
|
||||
log_printf (_("[date not given]"));
|
||||
log_printf (_(" using certificate ID %08lX\n"),
|
||||
log_printf (_(" using certificate ID 0x%08lX\n"),
|
||||
gpgsm_get_short_fingerprint (cert));
|
||||
|
||||
|
||||
@ -432,12 +434,14 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, FILE *out_fp)
|
||||
gcry_md_close (md);
|
||||
goto next_signer;
|
||||
}
|
||||
rc = gpgsm_check_cms_signature (cert, sigval, md, algo);
|
||||
rc = gpgsm_check_cms_signature (cert, sigval, md, algo,
|
||||
&info_pkalgo);
|
||||
gcry_md_close (md);
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = gpgsm_check_cms_signature (cert, sigval, data_md, algo);
|
||||
rc = gpgsm_check_cms_signature (cert, sigval, data_md, algo,
|
||||
&info_pkalgo);
|
||||
}
|
||||
|
||||
if (rc)
|
||||
@ -460,7 +464,10 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, FILE *out_fp)
|
||||
|
||||
if (DBG_X509)
|
||||
log_debug ("signature okay - checking certs\n");
|
||||
rc = gpgsm_validate_chain (ctrl, cert, keyexptime, 0, NULL, 0);
|
||||
rc = gpgsm_validate_chain (ctrl, cert,
|
||||
*sigtime? sigtime : "19700101T000000",
|
||||
keyexptime, 0,
|
||||
NULL, 0, &verifyflags);
|
||||
{
|
||||
char *fpr, *buf, *tstr;
|
||||
|
||||
@ -477,10 +484,10 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, FILE *out_fp)
|
||||
|
||||
fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
|
||||
tstr = strtimestamp_r (sigtime);
|
||||
buf = xmalloc ( strlen(fpr) + strlen (tstr) + 120);
|
||||
sprintf (buf, "%s %s %s %s", fpr, tstr,
|
||||
*sigtime? sigtime : "0",
|
||||
*keyexptime? keyexptime : "0" );
|
||||
buf = xasprintf ("%s %s %s %s 0 0 %d %d 00", fpr, tstr,
|
||||
*sigtime? sigtime : "0",
|
||||
*keyexptime? keyexptime : "0",
|
||||
info_pkalgo, algo);
|
||||
xfree (tstr);
|
||||
xfree (fpr);
|
||||
gpgsm_status (ctrl, STATUS_VALIDSIG, buf);
|
||||
@ -512,7 +519,32 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, FILE *out_fp)
|
||||
ksba_free (p);
|
||||
}
|
||||
|
||||
gpgsm_status (ctrl, STATUS_TRUST_FULLY, NULL);
|
||||
/* Print a note if this is a qualified signature. */
|
||||
{
|
||||
size_t qualbuflen;
|
||||
char qualbuffer[1];
|
||||
|
||||
rc = ksba_cert_get_user_data (cert, "is_qualified", &qualbuffer,
|
||||
sizeof (qualbuffer), &qualbuflen);
|
||||
if (!rc && qualbuflen)
|
||||
{
|
||||
if (*qualbuffer)
|
||||
{
|
||||
log_info (_("This is a qualified signature\n"));
|
||||
if (!opt.qualsig_approval)
|
||||
log_info
|
||||
(_("Note, that this software is not officially approved "
|
||||
"to create or verify such signatures.\n"));
|
||||
}
|
||||
}
|
||||
else if (gpg_err_code (rc) != GPG_ERR_NOT_FOUND)
|
||||
log_error ("get_user_data(is_qualified) failed: %s\n",
|
||||
gpg_strerror (rc));
|
||||
}
|
||||
|
||||
gpgsm_status (ctrl, STATUS_TRUST_FULLY,
|
||||
(verifyflags & VALIDATE_FLAG_CHAIN_MODEL)?
|
||||
"0 chain": "0 shell");
|
||||
|
||||
|
||||
next_signer:
|
||||
|
Loading…
x
Reference in New Issue
Block a user