mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-03 12:11:33 +01:00
dirmngr: Add options --tls and --systrust to the VALIDATE cmd.
* dirmngr/certcache.h (certlist_s, certlist_t): New. * dirmngr/certcache.c (read_certlist_from_stream): New. (release_certlist): New. * dirmngr/server.c (MAX_CERTLIST_LENGTH): New. (cmd_validate): Add options --tls and --systrust. Implement them using a kludge for now. * dirmngr/validate.c (validate_cert_chain): Support systrust checking. Add kludge to disable the CRL checking for tls mode. -- This can now be used to test a list of certificates as returned by TLS. Put the certs PEM encoded into a a file certlist.pem with the target certificate being the first. Then run gpg-connect-agent --dirmngr \ '/definqfile CERTLIST wiki-gnupg-chain.pem' \ 'validate --systrust --tls' /bye CRLS check has been disabled becuase we can't yet pass the systrust flag to the CRL checking code. Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
ed99af030d
commit
070211eb99
@ -225,6 +225,7 @@ cert_compute_fpr (ksba_cert_t cert, unsigned char *digest)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Cleanup one slot. This releases all resourses but keeps the actual
|
||||
slot in the cache marked for reuse. */
|
||||
static void
|
||||
@ -1669,3 +1670,92 @@ find_issuing_cert (ctrl_t ctrl, ksba_cert_t cert, ksba_cert_t *r_cert)
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Read a list of certificates in PEM format from stream FP and store
|
||||
* them on success at R_CERTLIST. On error NULL is stored at R_CERT
|
||||
* list and an error code returned. Note that even on success an
|
||||
* empty list of certificates can be returned (i.e. NULL stored at
|
||||
* R_CERTLIST) iff the input stream has no certificates. */
|
||||
gpg_error_t
|
||||
read_certlist_from_stream (certlist_t *r_certlist, estream_t fp)
|
||||
{
|
||||
gpg_error_t err;
|
||||
gnupg_ksba_io_t ioctx = NULL;
|
||||
ksba_reader_t reader;
|
||||
ksba_cert_t cert = NULL;
|
||||
certlist_t certlist = NULL;
|
||||
certlist_t cl, *cltail;
|
||||
|
||||
*r_certlist = NULL;
|
||||
|
||||
err = gnupg_ksba_create_reader (&ioctx,
|
||||
(GNUPG_KSBA_IO_PEM | GNUPG_KSBA_IO_MULTIPEM),
|
||||
fp, &reader);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
/* Loop to read all certificates from the stream. */
|
||||
cltail = &certlist;
|
||||
do
|
||||
{
|
||||
ksba_cert_release (cert);
|
||||
cert = NULL;
|
||||
err = ksba_cert_new (&cert);
|
||||
if (!err)
|
||||
err = ksba_cert_read_der (cert, reader);
|
||||
if (err)
|
||||
{
|
||||
if (gpg_err_code (err) == GPG_ERR_EOF)
|
||||
err = 0;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Append the certificate to the list. We also store the
|
||||
* fingerprint and check whether we have a cached certificate;
|
||||
* in that case the cached certificate is put into the list to
|
||||
* take advantage of a validation result which might be stored
|
||||
* in the cached certificate. */
|
||||
cl = xtrycalloc (1, sizeof *cl);
|
||||
if (!cl)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
cert_compute_fpr (cert, cl->fpr);
|
||||
cl->cert = get_cert_byfpr (cl->fpr);
|
||||
if (!cl->cert)
|
||||
{
|
||||
cl->cert = cert;
|
||||
cert = NULL;
|
||||
}
|
||||
*cltail = cl;
|
||||
cltail = &cl->next;
|
||||
ksba_reader_clear (reader, NULL, NULL);
|
||||
}
|
||||
while (!gnupg_ksba_reader_eof_seen (ioctx));
|
||||
|
||||
leave:
|
||||
ksba_cert_release (cert);
|
||||
gnupg_ksba_destroy_reader (ioctx);
|
||||
if (err)
|
||||
release_certlist (certlist);
|
||||
else
|
||||
*r_certlist = certlist;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Release the certificate list CL. */
|
||||
void
|
||||
release_certlist (certlist_t cl)
|
||||
{
|
||||
while (cl)
|
||||
{
|
||||
certlist_t next = cl->next;
|
||||
ksba_cert_release (cl->cert);
|
||||
cl = next;
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,6 @@ gpg_error_t cache_cert_silent (ksba_cert_t cert, void *fpr_buffer);
|
||||
* provided certificates are considered trusted. */
|
||||
gpg_error_t is_trusted_cert (ksba_cert_t cert, int with_systrust);
|
||||
|
||||
|
||||
/* Return a certificate object for the given fingerprint. FPR is
|
||||
expected to be a 20 byte binary SHA-1 fingerprint. If no matching
|
||||
certificate is available in the cache NULL is returned. The caller
|
||||
@ -100,5 +99,18 @@ gpg_error_t find_issuing_cert (ctrl_t ctrl,
|
||||
|
||||
|
||||
|
||||
/* A simple list of certificates. */
|
||||
struct certlist_s
|
||||
{
|
||||
struct certlist_s *next;
|
||||
ksba_cert_t cert;
|
||||
unsigned char fpr[20]; /* of the certificate. */
|
||||
};
|
||||
typedef struct certlist_s *certlist_t;
|
||||
|
||||
gpg_error_t read_certlist_from_stream (certlist_t *r_certlist, estream_t fp);
|
||||
void release_certlist (certlist_t cl);
|
||||
|
||||
|
||||
|
||||
#endif /*CERTCACHE_H*/
|
||||
|
@ -155,7 +155,8 @@ struct
|
||||
#define DBG_NETWORK (opt.debug & DBG_NETWORK_VALUE)
|
||||
#define DBG_LOOKUP (opt.debug & DBG_LOOKUP_VALUE)
|
||||
|
||||
/* A simple list of certificate references. */
|
||||
/* A simple list of certificate references. FIXME: Better use
|
||||
certlist_t also for references (Store NULL at .cert) */
|
||||
struct cert_ref_s
|
||||
{
|
||||
struct cert_ref_s *next;
|
||||
@ -163,6 +164,7 @@ struct cert_ref_s
|
||||
};
|
||||
typedef struct cert_ref_s *cert_ref_t;
|
||||
|
||||
|
||||
/* Forward references; access only through server.c. */
|
||||
struct server_local_s;
|
||||
|
||||
|
104
dirmngr/server.c
104
dirmngr/server.c
@ -60,6 +60,10 @@
|
||||
Dirmngr was a system service and not a user service. */
|
||||
#define MAX_CERT_LENGTH (16*1024)
|
||||
|
||||
/* The limit for the CERTLIST inquiry. We allow for up to 20
|
||||
* certificates but also take PEM encoding into account. */
|
||||
#define MAX_CERTLIST_LENGTH ((MAX_CERT_LENGTH * 20 * 4)/3)
|
||||
|
||||
/* The same goes for OpenPGP keyblocks, but here we need to allow for
|
||||
much longer blocks; a 200k keyblock is not too unusual for keys
|
||||
with a lot of signatures (e.g. 0x5b0358a2). 9C31503C6D866396 even
|
||||
@ -1729,7 +1733,7 @@ cmd_cachecert (assuan_context_t ctx, char *line)
|
||||
|
||||
|
||||
static const char hlp_validate[] =
|
||||
"VALIDATE\n"
|
||||
"VALIDATE [--systrust] [--tls]\n"
|
||||
"\n"
|
||||
"Validate a certificate using the certificate validation function\n"
|
||||
"used internally by dirmngr. This command is only useful for\n"
|
||||
@ -1739,20 +1743,38 @@ static const char hlp_validate[] =
|
||||
" INQUIRE TARGETCERT\n"
|
||||
"\n"
|
||||
"and the caller is expected to return the certificate for the\n"
|
||||
"request as a binary blob.";
|
||||
"request as a binary blob. The option --tls modifies this by asking\n"
|
||||
"for list of certificates with\n"
|
||||
"\n"
|
||||
" INQUIRE CERTLIST\n"
|
||||
"\n"
|
||||
"Here the first certificate is the target certificate, the remaining\n"
|
||||
"certificates are suggested intermediary certificates. All certifciates\n"
|
||||
"need to be PEM encoded.\n"
|
||||
"\n"
|
||||
"The option --systrust changes the behaviour to include the system\n"
|
||||
"provided root certificates as trust anchors.";
|
||||
static gpg_error_t
|
||||
cmd_validate (assuan_context_t ctx, char *line)
|
||||
{
|
||||
ctrl_t ctrl = assuan_get_pointer (ctx);
|
||||
gpg_error_t err;
|
||||
ksba_cert_t cert = NULL;
|
||||
certlist_t certlist = NULL;
|
||||
unsigned char *value = NULL;
|
||||
size_t valuelen;
|
||||
int systrust_mode, tls_mode;
|
||||
|
||||
(void)line;
|
||||
systrust_mode = has_option (line, "--systrust");
|
||||
tls_mode = has_option (line, "--tls");
|
||||
line = skip_options (line);
|
||||
|
||||
err = assuan_inquire (ctrl->server_local->assuan_ctx, "TARGETCERT",
|
||||
&value, &valuelen, MAX_CERT_LENGTH);
|
||||
if (tls_mode)
|
||||
err = assuan_inquire (ctrl->server_local->assuan_ctx, "CERTLIST",
|
||||
&value, &valuelen, MAX_CERTLIST_LENGTH);
|
||||
else
|
||||
err = assuan_inquire (ctrl->server_local->assuan_ctx, "TARGETCERT",
|
||||
&value, &valuelen, MAX_CERT_LENGTH);
|
||||
if (err)
|
||||
{
|
||||
log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
|
||||
@ -1761,6 +1783,27 @@ cmd_validate (assuan_context_t ctx, char *line)
|
||||
|
||||
if (!valuelen) /* No data returned; return a comprehensible error. */
|
||||
err = gpg_error (GPG_ERR_MISSING_CERT);
|
||||
else if (tls_mode)
|
||||
{
|
||||
estream_t fp;
|
||||
|
||||
fp = es_fopenmem_init (0, "rb", value, valuelen);
|
||||
if (!fp)
|
||||
err = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
err = read_certlist_from_stream (&certlist, fp);
|
||||
es_fclose (fp);
|
||||
if (!err && !certlist)
|
||||
err = gpg_error (GPG_ERR_MISSING_CERT);
|
||||
if (!err)
|
||||
{
|
||||
/* Extraxt the first certificate from the list. */
|
||||
cert = certlist->cert;
|
||||
ksba_cert_ref (cert);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err = ksba_cert_new (&cert);
|
||||
@ -1771,26 +1814,47 @@ cmd_validate (assuan_context_t ctx, char *line)
|
||||
if(err)
|
||||
goto leave;
|
||||
|
||||
/* If we have this certificate already in our cache, use the cached
|
||||
* version for validation because this will take care of any cached
|
||||
* results. */
|
||||
{
|
||||
unsigned char fpr[20];
|
||||
ksba_cert_t tmpcert;
|
||||
if (!tls_mode)
|
||||
{
|
||||
/* If we have this certificate already in our cache, use the
|
||||
* cached version for validation because this will take care of
|
||||
* any cached results. We don't need to do this in tls mode
|
||||
* because this has already been done for certificate in a
|
||||
* certlist_t. */
|
||||
unsigned char fpr[20];
|
||||
ksba_cert_t tmpcert;
|
||||
|
||||
cert_compute_fpr (cert, fpr);
|
||||
tmpcert = get_cert_byfpr (fpr);
|
||||
if (tmpcert)
|
||||
{
|
||||
ksba_cert_release (cert);
|
||||
cert = tmpcert;
|
||||
}
|
||||
}
|
||||
cert_compute_fpr (cert, fpr);
|
||||
tmpcert = get_cert_byfpr (fpr);
|
||||
if (tmpcert)
|
||||
{
|
||||
ksba_cert_release (cert);
|
||||
cert = tmpcert;
|
||||
}
|
||||
}
|
||||
|
||||
err = validate_cert_chain (ctrl, cert, NULL, VALIDATE_MODE_CERT, NULL);
|
||||
/* Quick hack to make verification work by inserting the supplied
|
||||
* certs into the cache. */
|
||||
if (tls_mode && certlist)
|
||||
{
|
||||
certlist_t cl;
|
||||
|
||||
for (cl = certlist->next; cl; cl = cl->next)
|
||||
cache_cert (cl->cert);
|
||||
}
|
||||
|
||||
|
||||
err = validate_cert_chain
|
||||
(ctrl, cert, NULL,
|
||||
tls_mode && systrust_mode ? VALIDATE_MODE_TLS_SYSTRUST :
|
||||
tls_mode ? VALIDATE_MODE_TLS :
|
||||
/**/ systrust_mode ? VALIDATE_MODE_CERT_SYSTRUST :
|
||||
/**/ VALIDATE_MODE_CERT,
|
||||
NULL);
|
||||
|
||||
leave:
|
||||
ksba_cert_release (cert);
|
||||
release_certlist (certlist);
|
||||
return leave_cmd (ctx, err);
|
||||
}
|
||||
|
||||
|
@ -233,8 +233,8 @@ check_revocations (ctrl_t ctrl, chain_item_t chain)
|
||||
int any_crl_too_old = 0;
|
||||
chain_item_t ci;
|
||||
|
||||
assert (ctrl->check_revocations_nest_level >= 0);
|
||||
assert (chain);
|
||||
log_assert (ctrl->check_revocations_nest_level >= 0);
|
||||
log_assert (chain);
|
||||
|
||||
if (ctrl->check_revocations_nest_level > 10)
|
||||
{
|
||||
@ -551,7 +551,9 @@ validate_cert_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
|
||||
if (err)
|
||||
goto leave; /* No. */
|
||||
|
||||
err = is_trusted_cert (subject_cert, 0);
|
||||
err = is_trusted_cert (subject_cert,
|
||||
(mode == VALIDATE_MODE_CERT_SYSTRUST
|
||||
|| mode == VALIDATE_MODE_TLS_SYSTRUST));
|
||||
if (!err)
|
||||
; /* Yes we trust this cert. */
|
||||
else if (gpg_err_code (err) == GPG_ERR_NOT_TRUSTED)
|
||||
@ -772,7 +774,9 @@ validate_cert_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
|
||||
* our validity results to avoid double work. Far worse a
|
||||
* catch-22 may happen for an improper setup hierarchy and we
|
||||
* need a way to break up such a deadlock. */
|
||||
err = check_revocations (ctrl, chain);
|
||||
if (mode != VALIDATE_MODE_TLS_SYSTRUST)
|
||||
err = check_revocations (ctrl, chain);
|
||||
#warning fix the above
|
||||
}
|
||||
|
||||
if (!err && opt.verbose)
|
||||
|
Loading…
x
Reference in New Issue
Block a user