core: Allow specifying an expiration date for key signatures
* src/context.h (struct gpgme_context): Add 'cert_expire'. * src/engine-gpg.c (append_args_from_cert_expire): New. (gpg_edit): Set option according to the new flag. * src/gpgme.c (gpgme_release): Free 'cert_expire'. (gpgme_set_ctx_flag, gpgme_get_ctx_flag): Add "cert-expire". * tests/gpg/Makefile.am (c_tests): Add new test. (gpg.conf): Write "allow-weak-key-signatures" to gpg.conf. * tests/gpg/t-edit-sign.c: New. -- The new context flag "cert-expire" allows setting the expiration date for key signatures created with gpgme_op_interact. GnuPG-bug-id: 5336, 5505
This commit is contained in:
parent
ab1d4ef580
commit
34d9defc42
3
NEWS
3
NEWS
@ -1,12 +1,15 @@
|
|||||||
Noteworthy changes in version 1.15.2 (unreleased)
|
Noteworthy changes in version 1.15.2 (unreleased)
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
|
||||||
|
* New context flag "cert-expire".
|
||||||
|
|
||||||
* cpp, qt: Add support for trust signatures. [#5421]
|
* cpp, qt: Add support for trust signatures. [#5421]
|
||||||
|
|
||||||
* qt: Add support for flags in LDAP server options. [#5217]
|
* qt: Add support for flags in LDAP server options. [#5217]
|
||||||
|
|
||||||
* Interface changes relative to the 1.15.1 release:
|
* Interface changes relative to the 1.15.1 release:
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
gpgme_set_ctx_flag EXTENDED: New flag 'cert-expire'.
|
||||||
cpp: SignKeyJob::setTrustSignature NEW.
|
cpp: SignKeyJob::setTrustSignature NEW.
|
||||||
cpp: TrustSignatureTrust NEW.
|
cpp: TrustSignatureTrust NEW.
|
||||||
cpp: GpgSignKeyEditInteractor::setTrustSignatureTrust NEW.
|
cpp: GpgSignKeyEditInteractor::setTrustSignatureTrust NEW.
|
||||||
|
@ -3179,6 +3179,14 @@ rebuilding the trust-db.
|
|||||||
This flag passes the option @option{--expert} to gpg key edit. This
|
This flag passes the option @option{--expert} to gpg key edit. This
|
||||||
can be used to get additional callbacks in @code{gpgme_op_edit}.
|
can be used to get additional callbacks in @code{gpgme_op_edit}.
|
||||||
|
|
||||||
|
@item "cert-expire"
|
||||||
|
@since{1.15.2}
|
||||||
|
The string given in @var{value} is passed to the GnuPG engine to set
|
||||||
|
the expiration time to use for key signature expiration. Valid values
|
||||||
|
are documented in the GnuPG manual and the gpg man page under
|
||||||
|
the option @option{--default-cert-expire}.
|
||||||
|
|
||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
This function returns @code{0} on success.
|
This function returns @code{0} on success.
|
||||||
|
@ -174,6 +174,9 @@ struct gpgme_context
|
|||||||
/* The optional trust-model override. */
|
/* The optional trust-model override. */
|
||||||
char *trust_model;
|
char *trust_model;
|
||||||
|
|
||||||
|
/* The optional expiration date of a certification. */
|
||||||
|
char *cert_expire;
|
||||||
|
|
||||||
/* The operation data hooked into the context. */
|
/* The operation data hooked into the context. */
|
||||||
ctx_op_data_t op_data;
|
ctx_op_data_t op_data;
|
||||||
|
|
||||||
|
@ -1960,6 +1960,27 @@ append_args_from_sig_notations (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gpgme_error_t
|
||||||
|
append_args_from_cert_expire (engine_gpg_t gpg, gpgme_ctx_t ctx)
|
||||||
|
{
|
||||||
|
gpgme_error_t err;
|
||||||
|
|
||||||
|
if (ctx->cert_expire)
|
||||||
|
{
|
||||||
|
/* Override ask-cert-expire set in the configuration, so that the specified
|
||||||
|
* default is actually used. */
|
||||||
|
err = add_arg (gpg, "--no-ask-cert-expire");
|
||||||
|
if (!err)
|
||||||
|
err = add_arg (gpg, "--default-cert-expire");
|
||||||
|
if (!err)
|
||||||
|
err = add_arg (gpg, ctx->cert_expire);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
err = 0;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static gpgme_error_t
|
static gpgme_error_t
|
||||||
gpg_edit (void *engine, int type, gpgme_key_t key, gpgme_data_t out,
|
gpg_edit (void *engine, int type, gpgme_key_t key, gpgme_data_t out,
|
||||||
gpgme_ctx_t ctx /* FIXME */)
|
gpgme_ctx_t ctx /* FIXME */)
|
||||||
@ -1975,6 +1996,8 @@ gpg_edit (void *engine, int type, gpgme_key_t key, gpgme_data_t out,
|
|||||||
err = append_args_from_signers (gpg, ctx);
|
err = append_args_from_signers (gpg, ctx);
|
||||||
if (!err)
|
if (!err)
|
||||||
err = append_args_from_sig_notations (gpg, ctx, NOTATION_FLAG_CERT);
|
err = append_args_from_sig_notations (gpg, ctx, NOTATION_FLAG_CERT);
|
||||||
|
if (!err)
|
||||||
|
err = append_args_from_cert_expire (gpg, ctx);
|
||||||
if (!err)
|
if (!err)
|
||||||
err = add_arg (gpg, type == 0 ? "--edit-key" : "--card-edit");
|
err = add_arg (gpg, type == 0 ? "--edit-key" : "--card-edit");
|
||||||
if (!err)
|
if (!err)
|
||||||
|
12
src/gpgme.c
12
src/gpgme.c
@ -253,6 +253,7 @@ gpgme_release (gpgme_ctx_t ctx)
|
|||||||
free (ctx->request_origin);
|
free (ctx->request_origin);
|
||||||
free (ctx->auto_key_locate);
|
free (ctx->auto_key_locate);
|
||||||
free (ctx->trust_model);
|
free (ctx->trust_model);
|
||||||
|
free (ctx->cert_expire);
|
||||||
_gpgme_engine_info_release (ctx->engine_info);
|
_gpgme_engine_info_release (ctx->engine_info);
|
||||||
ctx->engine_info = NULL;
|
ctx->engine_info = NULL;
|
||||||
DESTROY_LOCK (ctx->lock);
|
DESTROY_LOCK (ctx->lock);
|
||||||
@ -578,6 +579,13 @@ gpgme_set_ctx_flag (gpgme_ctx_t ctx, const char *name, const char *value)
|
|||||||
{
|
{
|
||||||
ctx->extended_edit = abool;
|
ctx->extended_edit = abool;
|
||||||
}
|
}
|
||||||
|
else if (!strcmp (name, "cert-expire"))
|
||||||
|
{
|
||||||
|
free (ctx->cert_expire);
|
||||||
|
ctx->cert_expire = strdup (value);
|
||||||
|
if (!ctx->cert_expire)
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
err = gpg_error (GPG_ERR_UNKNOWN_NAME);
|
err = gpg_error (GPG_ERR_UNKNOWN_NAME);
|
||||||
|
|
||||||
@ -647,6 +655,10 @@ gpgme_get_ctx_flag (gpgme_ctx_t ctx, const char *name)
|
|||||||
{
|
{
|
||||||
return ctx->extended_edit ? "1":"";
|
return ctx->extended_edit ? "1":"";
|
||||||
}
|
}
|
||||||
|
else if (!strcmp (name, "cert-expire"))
|
||||||
|
{
|
||||||
|
return ctx->cert_expire? ctx->cert_expire : "";
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ c_tests = \
|
|||||||
t-encrypt t-encrypt-sym t-encrypt-sign t-sign t-signers \
|
t-encrypt t-encrypt-sym t-encrypt-sign t-sign t-signers \
|
||||||
t-decrypt t-verify t-decrypt-verify t-sig-notation t-export \
|
t-decrypt t-verify t-decrypt-verify t-sig-notation t-export \
|
||||||
t-import t-edit t-keylist t-keylist-sig t-keylist-secret-sig t-wait \
|
t-import t-edit t-keylist t-keylist-sig t-keylist-secret-sig t-wait \
|
||||||
t-encrypt-large t-file-name t-gpgconf t-encrypt-mixed \
|
t-encrypt-large t-file-name t-gpgconf t-encrypt-mixed t-edit-sign \
|
||||||
$(tests_unix)
|
$(tests_unix)
|
||||||
|
|
||||||
TESTS = initial.test $(c_tests) final.test
|
TESTS = initial.test $(c_tests) final.test
|
||||||
@ -104,6 +104,8 @@ pubring-stamp: $(srcdir)/pubdemo.asc gpg-sample.stamp
|
|||||||
gpg.conf:
|
gpg.conf:
|
||||||
# This is required for t-sig-notations.
|
# This is required for t-sig-notations.
|
||||||
echo no-force-v3-sigs > ./gpg.conf
|
echo no-force-v3-sigs > ./gpg.conf
|
||||||
|
# This is required for t-edit-sign.
|
||||||
|
echo allow-weak-key-signatures >> ./gpg.conf
|
||||||
|
|
||||||
gpg-agent.conf:
|
gpg-agent.conf:
|
||||||
# This is required for gpg2, which does not support command fd for the
|
# This is required for gpg2, which does not support command fd for the
|
||||||
|
201
tests/gpg/t-edit-sign.c
Normal file
201
tests/gpg/t-edit-sign.c
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
/* t-edit-sign.c - Regression test.
|
||||||
|
* Copyright (C) 2000 Werner Koch (dd9jn)
|
||||||
|
* Copyright (C) 2001, 2002, 2003, 2004, 2021 g10 Code GmbH
|
||||||
|
* Software engineering by Ingo Klöcker <dev@ingo-kloecker.de>
|
||||||
|
*
|
||||||
|
* This file is part of GPGME.
|
||||||
|
*
|
||||||
|
* GPGME 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.
|
||||||
|
*
|
||||||
|
* GPGME 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 <https://gnu.org/licenses/>.
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* We need to include config.h so that we know whether we are building
|
||||||
|
with large file system (LFS) support. */
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <gpgme.h>
|
||||||
|
|
||||||
|
#include "t-support.h"
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
flush_data (gpgme_data_t dh)
|
||||||
|
{
|
||||||
|
char buf[100];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = gpgme_data_seek (dh, 0, SEEK_SET);
|
||||||
|
if (ret)
|
||||||
|
fail_if_err (gpgme_error_from_errno (errno));
|
||||||
|
while ((ret = gpgme_data_read (dh, buf, 100)) > 0)
|
||||||
|
fwrite (buf, ret, 1, stdout);
|
||||||
|
if (ret < 0)
|
||||||
|
fail_if_err (gpgme_error_from_errno (errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gpgme_error_t
|
||||||
|
interact_fnc (void *opaque, const char *status, const char *args, int fd)
|
||||||
|
{
|
||||||
|
const char *result = NULL;
|
||||||
|
gpgme_data_t out = (gpgme_data_t) opaque;
|
||||||
|
|
||||||
|
fputs ("[-- Response --]\n", stdout);
|
||||||
|
flush_data (out);
|
||||||
|
|
||||||
|
fprintf (stdout, "[-- Code: %s, %s --]\n", status, args);
|
||||||
|
|
||||||
|
if (fd >= 0)
|
||||||
|
{
|
||||||
|
if (!strcmp (args, "keyedit.prompt"))
|
||||||
|
{
|
||||||
|
static int step = 0;
|
||||||
|
|
||||||
|
switch (step)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
result = "fpr";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
/* This fixes the primary user ID so the keylisting
|
||||||
|
tests will have predictable output. */
|
||||||
|
result = "1";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
result = "sign";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
result = "quit";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
step++;
|
||||||
|
}
|
||||||
|
else if (!strcmp (args, "keyedit.save.okay"))
|
||||||
|
result = "Y";
|
||||||
|
else if (!strcmp (args, "sign_uid.okay"))
|
||||||
|
result = "Y";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
gpgme_io_writen (fd, result, strlen (result));
|
||||||
|
gpgme_io_writen (fd, "\n", 1);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char **argv)
|
||||||
|
{
|
||||||
|
gpgme_ctx_t ctx;
|
||||||
|
gpgme_error_t err;
|
||||||
|
gpgme_data_t out = NULL;
|
||||||
|
const char *signer_fpr = "A0FF4590BB6122EDEF6E3C542D727CC768697734"; /* Alpha Test */
|
||||||
|
gpgme_key_t signing_key = NULL;
|
||||||
|
const char *key_fpr = "D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2"; /* Bravo Test */
|
||||||
|
gpgme_key_t key = NULL;
|
||||||
|
gpgme_key_t signed_key = NULL;
|
||||||
|
gpgme_user_id_t signed_uid = NULL;
|
||||||
|
gpgme_key_sig_t key_sig = NULL;
|
||||||
|
char *agent_info;
|
||||||
|
int mode;
|
||||||
|
|
||||||
|
(void)argc;
|
||||||
|
(void)argv;
|
||||||
|
|
||||||
|
init_gpgme (GPGME_PROTOCOL_OpenPGP);
|
||||||
|
|
||||||
|
err = gpgme_new (&ctx);
|
||||||
|
fail_if_err (err);
|
||||||
|
|
||||||
|
/* Sign the key */
|
||||||
|
agent_info = getenv("GPG_AGENT_INFO");
|
||||||
|
if (!(agent_info && strchr (agent_info, ':')))
|
||||||
|
gpgme_set_passphrase_cb (ctx, passphrase_cb, 0);
|
||||||
|
|
||||||
|
err = gpgme_get_key (ctx, signer_fpr, &signing_key, 1);
|
||||||
|
fail_if_err (err);
|
||||||
|
err = gpgme_signers_add (ctx, signing_key);
|
||||||
|
fail_if_err (err);
|
||||||
|
|
||||||
|
err = gpgme_set_ctx_flag (ctx, "cert-expire", "42d");
|
||||||
|
fail_if_err (err);
|
||||||
|
|
||||||
|
err = gpgme_get_key (ctx, key_fpr, &key, 0);
|
||||||
|
fail_if_err (err);
|
||||||
|
|
||||||
|
err = gpgme_data_new (&out);
|
||||||
|
fail_if_err (err);
|
||||||
|
|
||||||
|
err = gpgme_op_interact (ctx, key, 0, interact_fnc, out, out);
|
||||||
|
fail_if_err (err);
|
||||||
|
|
||||||
|
fputs ("[-- Last response --]\n", stdout);
|
||||||
|
flush_data (out);
|
||||||
|
|
||||||
|
gpgme_data_release (out);
|
||||||
|
gpgme_key_unref (key);
|
||||||
|
gpgme_key_unref (signing_key);
|
||||||
|
|
||||||
|
/* Verify the key signature */
|
||||||
|
mode = gpgme_get_keylist_mode (ctx);
|
||||||
|
mode |= GPGME_KEYLIST_MODE_SIGS;
|
||||||
|
err = gpgme_set_keylist_mode (ctx, mode);
|
||||||
|
fail_if_err (err);
|
||||||
|
err = gpgme_get_key (ctx, key_fpr, &signed_key, 0);
|
||||||
|
fail_if_err (err);
|
||||||
|
|
||||||
|
signed_uid = key->uids;
|
||||||
|
if (!signed_uid)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Signed key has no user IDs\n");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
if (!signed_uid->signatures || !signed_uid->signatures->next)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Signed user ID has less signatures than expected\n");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
key_sig = signed_uid->signatures->next;
|
||||||
|
if (strcmp ("2D727CC768697734", key_sig->keyid))
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Unexpected key ID in second user ID sig: %s\n",
|
||||||
|
key_sig->keyid);
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
if (key_sig->expires != key_sig->timestamp + 42*86400L)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Key signature unexpectedly does not expire in 42 days\n");
|
||||||
|
fprintf (stderr, "signature date: %ld, expiration date: %ld\n",
|
||||||
|
key_sig->timestamp, key_sig->expires);
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
gpgme_key_unref (signed_key);
|
||||||
|
gpgme_release (ctx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user