diff --git a/src/gpgsm.c b/src/gpgsm.c
index c315460..026e394 100644
--- a/src/gpgsm.c
+++ b/src/gpgsm.c
@@ -1,131 +1,141 @@
/* gpgsm.c - Talking to gpgsm.
* Copyright (C) 2006, 2008 g10 Code GmbH
*
* This file is part of Scute.
*
* Scute is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Scute is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see .
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#if HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include "cryptoki.h"
#include "support.h"
#include "cert.h"
#include "agent.h"
#include "gpgsm.h"
#include "debug.h"
/* Communication object for search_cb. */
struct search_cb_parm
{
bool found; /* Set to true if a private key object was found. */
+ int depth; /* To track the recursion. */
cert_get_cb_t cert_get_cb;
void *hook;
bool with_chain;
const char *grip;
};
static gpg_error_t
search_cb (void *hook, struct cert *cert)
{
struct search_cb_parm *ctx = hook;
gpg_error_t err = 0;
CK_ATTRIBUTE_PTR attrp;
CK_ULONG attr_countp;
/* Add the private key object only once. */
if (!ctx->found)
{
err = scute_attr_prv (cert, ctx->grip, &attrp, &attr_countp);
if (err)
return err;
err = (*ctx->cert_get_cb) (ctx->hook, attrp, attr_countp);
if (err)
{
scute_attr_free (attrp, attr_countp);
return err;
}
ctx->found = true;
}
/* Add the certificate chain recursively before adding the
certificate. But ignore errors. If the chain is incomplete, we
might still be able to proceed, for example with client
authentication. */
if (ctx->with_chain && strcmp (cert->chain_id, cert->fpr))
- scute_gpgsm_search_certs (KEYLIST_BY_FPR, cert->chain_id, search_cb, ctx);
+ {
+ ctx->depth++;
+ if (ctx->depth > 7)
+ {
+ DEBUG (DBG_INFO, "search_cb: certificate chain too long\n");
+ return gpg_error (GPG_ERR_BAD_CERT_CHAIN);
+ }
+ scute_gpgsm_search_certs (KEYLIST_BY_FPR, cert->chain_id, search_cb, ctx);
+ }
/* Turn this certificate into a certificate object. */
err = scute_attr_cert (cert, ctx->grip, &attrp, &attr_countp);
if (err)
return err;
err = (*ctx->cert_get_cb) (ctx->hook, attrp, attr_countp);
if (err)
scute_attr_free (attrp, attr_countp);
/* DEBUG (DBG_INFO, "scute_gpgsm_get_cert[%lu]: search_cb result=%d", */
/* (unsigned long)getpid(), err); */
return err;
}
/* Create the attributes required for a new certificate object.
* KINFO->GRIP is used to find the certificate in the local key store
* of gpgsm.
*
* Returns allocated attributes for the certificate object in ATTRP
* and ATTR_COUNTP, and for the private key object in PRV_ATTRP and
* PRV_ATTR_COUNTP. */
gpg_error_t
scute_gpgsm_get_cert (const char *grip, cert_get_cb_t cert_get_cb, void *hook)
{
gpg_error_t err;
struct search_cb_parm search;
search.found = false;
+ search.depth = 0;
search.cert_get_cb = cert_get_cb;
search.hook = hook;
search.with_chain = false;
search.grip = grip;
DEBUG (DBG_INFO, "scute_gpgsm_get_cert: grip='%s'", grip);
search.with_chain = true;
err = scute_gpgsm_search_certs (KEYLIST_BY_GRIP, grip, search_cb, &search);
if (!err)
{
if (!search.found)
err = gpg_error (GPG_ERR_NOT_FOUND);
}
return err;
}