summaryrefslogtreecommitdiffstats
path: root/dirmngr/server.c
diff options
context:
space:
mode:
Diffstat (limited to 'dirmngr/server.c')
-rw-r--r--dirmngr/server.c104
1 files changed, 84 insertions, 20 deletions
diff --git a/dirmngr/server.c b/dirmngr/server.c
index bc373f5b0..05ef439a1 100644
--- a/dirmngr/server.c
+++ b/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;
+ }
+ }
+
+ /* 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);
+ }
- 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);
+ 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);
}