diff options
author | Werner Koch <wk@gnupg.org> | 2024-02-10 14:24:50 +0100 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2024-02-10 14:26:55 +0100 |
commit | 302afcb6f6af1dc88357acacfaa6829f0717b1c6 (patch) | |
tree | f198426cf8c1713df2c7f0ae6939fc9fad12667e | |
parent | doc: Suggest the use of a fingerprint for --default-key. (diff) | |
download | gnupg2-302afcb6f6af1dc88357acacfaa6829f0717b1c6.tar.xz gnupg2-302afcb6f6af1dc88357acacfaa6829f0717b1c6.zip |
gpg: Add option --assert-pubkey_algo.
* g10/keyid.c (parse_one_algo_string): New.
(compare_pubkey_string_part): New.
(compare_pubkey_string): New.
* g10/verify.c (check_assert_signer_list): New.
* g10/mainproc.c (check_sig_and_print): Call check_assert_pubkey_algo.
* g10/options.h (opt): Add field assert_pubkey_algos.
* g10/gpg.c (oAssertPubkeyAlgo): New.
(opts): Add "--assert-pubkey_algo".
(assert_pubkey_algo_false): New.
(main): Parse option.
(g10_exit): Reorder RC modifications. Check assert_pubkey_algo_false.
* common/status.h (ASSERT_PUBKEY_ALGOS): new.
* common/t-support.h (LEAN_T_SUPPORT): Use a simplified version if
this macro is set.
* g10/gpgv.c (oAssertPubkeyAlgo): New.
(opts): Add "--assert-pubkey_algo".
(assert_pubkey_algo_false): New.
(main): Parse option.
(g10_exit): Check assert_pubkey_algo_false.
* g10/t-keyid.c: New.
* g10/Makefile.am: Add t-keyid.
* g10/test-stubs.c: Add assert_pubkey_algos and assert_signer_list and
remove from other tests.
(check_assert_signer_list): Ditto.
(check_assert_pubkey_algo): Ditto.
--
GnuPG-bug-id: 6946
-rw-r--r-- | common/status.h | 1 | ||||
-rw-r--r-- | common/t-support.h | 13 | ||||
-rw-r--r-- | doc/DETAILS | 6 | ||||
-rw-r--r-- | doc/gpg.texi | 23 | ||||
-rw-r--r-- | doc/gpgv.texi | 5 | ||||
-rw-r--r-- | g10/Makefile.am | 6 | ||||
-rw-r--r-- | g10/gpg.c | 39 | ||||
-rw-r--r-- | g10/gpgv.c | 32 | ||||
-rw-r--r-- | g10/keydb.h | 1 | ||||
-rw-r--r-- | g10/keyid.c | 124 | ||||
-rw-r--r-- | g10/main.h | 2 | ||||
-rw-r--r-- | g10/mainproc.c | 19 | ||||
-rw-r--r-- | g10/options.h | 4 | ||||
-rw-r--r-- | g10/t-keydb-get-keyblock.c | 9 | ||||
-rw-r--r-- | g10/t-keydb.c | 10 | ||||
-rw-r--r-- | g10/t-keyid.c | 129 | ||||
-rw-r--r-- | g10/t-stutter.c | 9 | ||||
-rw-r--r-- | g10/test-stubs.c | 18 | ||||
-rw-r--r-- | g10/test.c | 1 | ||||
-rw-r--r-- | g10/verify.c | 33 |
20 files changed, 425 insertions, 59 deletions
diff --git a/common/status.h b/common/status.h index d249174d1..0a1266d3c 100644 --- a/common/status.h +++ b/common/status.h @@ -54,6 +54,7 @@ enum STATUS_NEED_PASSPHRASE, STATUS_VALIDSIG, STATUS_ASSERT_SIGNER, + STATUS_ASSERT_PUBKEY_ALGO, STATUS_SIG_ID, STATUS_ENC_TO, STATUS_NODATA, diff --git a/common/t-support.h b/common/t-support.h index 7aa46c00c..aa1b560fc 100644 --- a/common/t-support.h +++ b/common/t-support.h @@ -31,6 +31,8 @@ #ifndef GNUPG_COMMON_T_SUPPORT_H #define GNUPG_COMMON_T_SUPPORT_H 1 +#ifndef LEAN_T_SUPPORT + #ifdef GCRYPT_VERSION #error The regression tests should not include with gcrypt.h #endif @@ -45,11 +47,6 @@ # define getenv(a) (NULL) #endif -#ifndef DIM -# define DIM(v) (sizeof(v)/sizeof((v)[0])) -# define DIMof(type,member) DIM(((type *)0)->member) -#endif - /* Replacement prototypes. */ void *gcry_xmalloc (size_t n); @@ -65,6 +62,12 @@ void gcry_free (void *a); #define xstrdup(a) gcry_xstrdup ( (a) ) #define xfree(a) gcry_free ( (a) ) +#endif /* LEAN_T_SUPPORT */ + +#ifndef DIM +# define DIM(v) (sizeof(v)/sizeof((v)[0])) +# define DIMof(type,member) DIM(((type *)0)->member) +#endif /* Macros to print the result of a test. */ #define pass() do { ; } while(0) diff --git a/doc/DETAILS b/doc/DETAILS index fd95e511c..29e39708b 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -527,6 +527,12 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB: --assert-signer is used. The fingerprint is printed with uppercase hex digits. +*** ASSERT_PUBKEY_ALGO <fingerprint> <state> <algostr> + This is emitted when option --assert-pubkey-algo is used and the + signing algorithms is accepted according to that list if state is + 1 or denied if state is 0. The fingerprint is printed with + uppercase hex digits. + *** SIG_ID <radix64_string> <sig_creation_date> <sig-timestamp> This is emitted only for signatures of class 0 or 1 which have been verified okay. The string is a signature id and may be used diff --git a/doc/gpg.texi b/doc/gpg.texi index 2f5b613d8..26e0ebdcd 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -1917,6 +1917,29 @@ is guaranteed to return with an exit code of 0 if and only if a signature has been encountered, is valid, and the key matches one of the fingerprints given by this option. +@item --assert-pubkey-algo @var{algolist} +@opindex assert-pubkey-algo +During data signature verification this options checks whether the +used public key algorithm matches the algorithms given by +@var{algolist}. This option can be given multiple times to +concatenate more algorithms to the list; the delimiter of the list are +either commas or spaces. + +The algorithm names given in the list may either be verbatim names +like "ed25519" with an optional leading single equal sign, or being +prefixed with ">", ">=", "<=", or "<". That prefix operator is +applied to the number part of the algorithm name; for example 2048 in +"rsa2048" or 384 in "brainpoolP384r1". If the the leading non-digits +in the name matches, the prefix operator is used to compare the number +part, a trailing suffix is ignored in this case. For example an +algorithm list ">rsa3000, >=brainpool384r1, =ed25519" allows RSA +signatures with more that 3000 bits, Brainpool curves 384 and 512, +and the ed25519 algorithm. + +With this option gpg (and also gpgv) is guaranteed to return with an +exit code of 0 if and only if all valid signatures on data are made +using a matching algorithm from the given list. + @item --auto-key-locate @var{mechanisms} @itemx --no-auto-key-locate diff --git a/doc/gpgv.texi b/doc/gpgv.texi index 2dd9576b6..54ab23383 100644 --- a/doc/gpgv.texi +++ b/doc/gpgv.texi @@ -140,6 +140,10 @@ This option enables a mode in which filenames of the form @file{-&n}, where n is a non-negative decimal number, refer to the file descriptor n and not to a file with that name. +@item --assert-pubkey-algo @var{algolist} +@opindex assert-pubkey-algo +This option works in the same way as described for @command{gpg}. + @end table @mansect return value @@ -190,4 +194,3 @@ The default keyring with the allowed keys. @mansect see also @command{gpg}(1) @include see-also-note.texi - diff --git a/g10/Makefile.am b/g10/Makefile.am index c5691f551..e8d8e9017 100644 --- a/g10/Makefile.am +++ b/g10/Makefile.am @@ -183,7 +183,7 @@ gpgv_LDFLAGS = t_common_ldadd = -module_tests = t-rmd160 t-keydb t-keydb-get-keyblock t-stutter +module_tests = t-rmd160 t-keydb t-keydb-get-keyblock t-stutter t-keyid t_rmd160_SOURCES = t-rmd160.c rmd160.c t_rmd160_LDADD = $(t_common_ldadd) t_keydb_SOURCES = t-keydb.c test-stubs.c $(common_source) @@ -200,6 +200,10 @@ t_stutter_SOURCES = t-stutter.c test-stubs.c \ t_stutter_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \ $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) $(NETLIBS) \ $(LIBICONV) $(t_common_ldadd) +t_keyid_SOURCES = t-keyid.c test-stubs.c $(common_source) +t_keyid_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \ + $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) $(NETLIBS) \ + $(LIBICONV) $(t_common_ldadd) $(PROGRAMS): $(needed_libs) ../common/libgpgrl.a @@ -451,6 +451,7 @@ enum cmd_and_opt_values oCompatibilityFlags, oAddDesigRevoker, oAssertSigner, + oAssertPubkeyAlgo, oKbxBufferSize, oNoop @@ -715,6 +716,7 @@ static gpgrt_opt_t opts[] = { #endif ARGPARSE_s_s (oAddDesigRevoker, "add-desig-revoker", "@"), ARGPARSE_s_s (oAssertSigner, "assert-signer", "@"), + ARGPARSE_s_s (oAssertPubkeyAlgo,"assert-pubkey-algo", "@"), ARGPARSE_header ("Input", N_("Options controlling the input")), @@ -1044,9 +1046,12 @@ static struct compatibility_flags_s compatibility_flags [] = /* Can be set to true to force gpg to return with EXIT_FAILURE. */ int g10_errors_seen = 0; -/* If opt.assert_signer_list is used and this variabale is not true +/* If opt.assert_signer_list is used and this variable is not true * gpg will be forced to return EXIT_FAILURE. */ int assert_signer_true = 0; +/* If opt.assert_pubkey_algo is used and this variable is not true + * gpg will be forced to return EXIT_FAILURE. */ +int assert_pubkey_algo_false = 0; static int utf8_strings = @@ -3770,6 +3775,18 @@ main (int argc, char **argv) add_to_strlist (&opt.assert_signer_list, pargs.r.ret_str); break; + case oAssertPubkeyAlgo: + if (!opt.assert_pubkey_algos) + opt.assert_pubkey_algos = xstrdup (pargs.r.ret_str); + else + { + char *tmp = opt.assert_pubkey_algos; + opt.assert_pubkey_algos = xstrconcat (tmp, ",", + pargs.r.ret_str, NULL); + xfree (tmp); + } + break; + case oKbxBufferSize: keybox_set_buffersize (pargs.r.ret_ulong, 0); break; @@ -5472,6 +5489,17 @@ emergency_cleanup (void) void g10_exit( int rc ) { + if (rc) + ; + else if (log_get_errorcount(0)) + rc = 2; + else if (g10_errors_seen) + rc = 1; + else if (opt.assert_signer_list && !assert_signer_true) + rc = 1; + else if (opt.assert_pubkey_algos && assert_pubkey_algo_false) + rc = 1; + /* If we had an error but not printed an error message, do it now. * Note that write_status_failure will never print a second failure * status line. */ @@ -5496,15 +5524,6 @@ g10_exit( int rc ) gnupg_block_all_signals (); emergency_cleanup (); - if (rc) - ; - else if (log_get_errorcount(0)) - rc = 2; - else if (g10_errors_seen) - rc = 1; - else if (opt.assert_signer_list && !assert_signer_true) - rc = 1; - exit (rc); } diff --git a/g10/gpgv.c b/g10/gpgv.c index f2895563e..c3b09f752 100644 --- a/g10/gpgv.c +++ b/g10/gpgv.c @@ -68,6 +68,7 @@ enum cmd_and_opt_values { oWeakDigest, oEnableSpecialFilenames, oDebug, + oAssertPubkeyAlgo, aTest }; @@ -91,6 +92,7 @@ static gpgrt_opt_t opts[] = { N_("|ALGO|reject signatures made with ALGO")), ARGPARSE_s_n (oEnableSpecialFilenames, "enable-special-filenames", "@"), ARGPARSE_s_s (oDebug, "debug", "@"), + ARGPARSE_s_s (oAssertPubkeyAlgo,"assert-pubkey-algo", "@"), ARGPARSE_end () }; @@ -119,6 +121,7 @@ static struct debug_flags_s debug_flags [] = int g10_errors_seen = 0; int assert_signer_true = 0; +int assert_pubkey_algo_false = 0; static char * make_libversion (const char *libname, const char *(*getfnc)(const char*)) @@ -251,6 +254,19 @@ main( int argc, char **argv ) case oEnableSpecialFilenames: enable_special_filenames (); break; + + case oAssertPubkeyAlgo: + if (!opt.assert_pubkey_algos) + opt.assert_pubkey_algos = xstrdup (pargs.r.ret_str); + else + { + char *tmp = opt.assert_pubkey_algos; + opt.assert_pubkey_algos = xstrconcat (tmp, ",", + pargs.r.ret_str, NULL); + xfree (tmp); + } + break; + default : pargs.err = ARGPARSE_PRINT_ERROR; break; } } @@ -288,10 +304,18 @@ main( int argc, char **argv ) void -g10_exit( int rc ) -{ - rc = rc? rc : log_get_errorcount(0)? 2 : g10_errors_seen? 1 : 0; - exit(rc ); +g10_exit (int rc) +{ + if (rc) + ; + else if (log_get_errorcount(0)) + rc = 2; + else if (g10_errors_seen) + rc = 1; + else if (opt.assert_pubkey_algos && assert_pubkey_algo_false) + rc = 1; + + exit (rc); } diff --git a/g10/keydb.h b/g10/keydb.h index b18f6e93a..798c24da3 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -487,6 +487,7 @@ const char *key_origin_string (int origin); /*-- keyid.c --*/ int pubkey_letter( int algo ); char *pubkey_string (PKT_public_key *pk, char *buffer, size_t bufsize); +int compare_pubkey_string (const char *astr, const char *bstr); #define PUBKEY_STRING_SIZE 32 u32 v3_keyid (gcry_mpi_t a, u32 *ki); void hash_public_key( gcry_md_hd_t md, PKT_public_key *pk ); diff --git a/g10/keyid.c b/g10/keyid.c index 89bba0d7a..ce977de0b 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -140,6 +140,130 @@ pubkey_string (PKT_public_key *pk, char *buffer, size_t bufsize) } +/* Helper for compare_pubkey_string. This skips leading spaces, + * commas and optional condition operators and returns a pointer to + * the first non-space character or NULL in case of an error. The + * length of a prefix consisting of letters is then returned ar PFXLEN + * and the value of the number (e.g. 384 for "brainpoolP384r1") at + * NUMBER. R_LENGTH receives the entire length of the algorithm name + * which is terminated by a space, nul, or a comma. If R_CONDITION is + * not NULL, 0 is stored for a leading "=", 1 for a ">", 2 for a ">=", + * -1 for a "<", and -2 for a "<=". If R_CONDITION is NULL no + * condition prefix is allowed. */ +static const char * +parse_one_algo_string (const char *str, size_t *pfxlen, unsigned int *number, + size_t *r_length, int *r_condition) +{ + int condition = 0; + const char *result; + + while (spacep (str) || *str ==',') + str++; + if (!r_condition) + ; + else if (*str == '>' && str[1] == '=') + condition = 2, str += 2; + else if (*str == '>' ) + condition = 1, str += 1; + else if (*str == '<' && str[1] == '=') + condition = -2, str += 2; + else if (*str == '<') + condition = -1, str += 1; + else if (*str == '=') /* Default. */ + str += 1; + + if (!alphap (str)) + return NULL; /* Error. */ + + *pfxlen = 1; + for (result = str++; alphap (str); str++) + ++*pfxlen; + while (*str == '-' || *str == '+') + str++; + *number = atoi (str); + while (*str && !spacep (str) && *str != ',') + str++; + + *r_length = str - result; + if (r_condition) + *r_condition = condition; + return result; +} + +/* Helper for compare_pubkey_string. If BPARSED is set to 0 on + * return, an error in ASTR or BSTR was found and further checks are + * not possible. */ +static int +compare_pubkey_string_part (const char *astr, const char *bstr_arg, + size_t *bparsed) +{ + const char *bstr = bstr_arg; + size_t alen, apfxlen, blen, bpfxlen; + unsigned int anumber, bnumber; + int condition; + + *bparsed = 0; + astr = parse_one_algo_string (astr, &apfxlen, &anumber, &alen, &condition); + if (!astr) + return 0; /* Invalid algorithm name. */ + bstr = parse_one_algo_string (bstr, &bpfxlen, &bnumber, &blen, &condition); + if (!bstr) + return 0; /* Invalid algorithm name. */ + *bparsed = blen + (bstr - bstr_arg); + if (apfxlen != bpfxlen || ascii_strncasecmp (astr, bstr, apfxlen)) + return 0; /* false. */ + switch (condition) + { + case 2: return anumber >= bnumber; + case 1: return anumber > bnumber; + case -1: return anumber < bnumber; + case -2: return anumber <= bnumber; + } + + return alen == blen && !ascii_strncasecmp (astr, bstr, alen); +} + + +/* Check whether ASTR matches the constraints given by BSTR. ASTR may + * be any algo string like "rsa2048", "ed25519" and BSTR may be a + * constraint which is in the simplest case just another algo string. + * BSTR may have more that one string in which case they are comma + * separated and any match will return true. It is possible to prefix + * BSTR with ">", ">=", "<=", or "<". That prefix operator is applied + * to the number part of the algorithm, i.e. the first sequence of + * digits found before end-of-string or a comma. Examples: + * + * | ASTR | BSTR | result | + * |----------+----------------------+--------| + * | rsa2048 | rsa2048 | true | + * | rsa2048 | >=rsa2048 | true | + * | rsa2048 | >rsa2048 | false | + * | ed25519 | >rsa1024 | false | + * | ed25519 | ed25519 | true | + * | nistp384 | >nistp256 | true | + * | nistp521 | >=rsa3072, >nistp384 | true | + */ +int +compare_pubkey_string (const char *astr, const char *bstr) +{ + size_t bparsed; + int result; + + while (*bstr) + { + result = compare_pubkey_string_part (astr, bstr, &bparsed); + if (result) + return 1; + if (!bparsed) + return 0; /* Syntax error in ASTR or BSTR. */ + bstr += bparsed; + } + + return 0; +} + + + /* Hash a public key and allow to specify the to be used format. * Note that if the v5 format is requested for a v4 key, a 0x04 as * version is hashed instead of the 0x05. */ diff --git a/g10/main.h b/g10/main.h index b29e23e51..2482fbde2 100644 --- a/g10/main.h +++ b/g10/main.h @@ -84,6 +84,7 @@ struct weakhash /*-- gpg.c --*/ extern int g10_errors_seen; extern int assert_signer_true; +extern int assert_pubkey_algo_false; #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) void g10_exit(int rc) __attribute__ ((__noreturn__)); @@ -494,6 +495,7 @@ int verify_signatures (ctrl_t ctrl, int nfiles, char **files ); int verify_files (ctrl_t ctrl, int nfiles, char **files ); int gpg_verify (ctrl_t ctrl, int sig_fd, int data_fd, estream_t out_fp); void check_assert_signer_list (const char *mainpkhex, const char *pkhex); +void check_assert_pubkey_algo (const char *algostr, const char *pkhex); /*-- decrypt.c --*/ int decrypt_message (ctrl_t ctrl, const char *filename ); diff --git a/g10/mainproc.c b/g10/mainproc.c index 430d7ff08..5f3f6df86 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -1876,6 +1876,8 @@ check_sig_and_print (CTX c, kbnode_t node) const void *extrahash = NULL; size_t extrahashlen = 0; kbnode_t included_keyblock = NULL; + char pkstrbuf[PUBKEY_STRING_SIZE] = { 0 }; + if (opt.skip_verify) { @@ -2409,8 +2411,14 @@ check_sig_and_print (CTX c, kbnode_t node) show_notation (sig, 0, 2, 0); } + /* Fill PKSTRBUF with the algostring in case we later need it. */ + if (pk) + pubkey_string (pk, pkstrbuf, sizeof pkstrbuf); + /* For good signatures print the VALIDSIG status line. */ - if (!rc && (is_status_enabled () || opt.assert_signer_list) && pk) + if (!rc && (is_status_enabled () + || opt.assert_signer_list + || opt.assert_pubkey_algos) && pk) { char pkhex[MAX_FINGERPRINT_LEN*2+1]; char mainpkhex[MAX_FINGERPRINT_LEN*2+1]; @@ -2432,6 +2440,8 @@ check_sig_and_print (CTX c, kbnode_t node) mainpkhex); /* Handle the --assert-signer option. */ check_assert_signer_list (mainpkhex, pkhex); + /* Handle the --assert-pubkey-algo option. */ + check_assert_pubkey_algo (pkstrbuf, pkhex); } /* Print compliance warning for Good signatures. */ @@ -2464,13 +2474,6 @@ check_sig_and_print (CTX c, kbnode_t node) if (opt.verbose) { - char pkstrbuf[PUBKEY_STRING_SIZE]; - - if (pk) - pubkey_string (pk, pkstrbuf, sizeof pkstrbuf); - else - *pkstrbuf = 0; - log_info (_("%s signature, digest algorithm %s%s%s\n"), sig->sig_class==0x00?_("binary"): sig->sig_class==0x01?_("textmode"):_("unknown"), diff --git a/g10/options.h b/g10/options.h index 146b78361..1e1110334 100644 --- a/g10/options.h +++ b/g10/options.h @@ -241,6 +241,10 @@ struct * modify to be uppercase if they represent a fingerrint */ strlist_t assert_signer_list; + /* A single string with the comma delimited args from + * --assert-pubkey_algo. */ + char *assert_pubkey_algos; + struct { /* If set, require an 0x19 backsig to be present on signatures diff --git a/g10/t-keydb-get-keyblock.c b/g10/t-keydb-get-keyblock.c index e40be9cc1..90ce6e9a6 100644 --- a/g10/t-keydb-get-keyblock.c +++ b/g10/t-keydb-get-keyblock.c @@ -67,12 +67,3 @@ do_test (int argc, char *argv[]) release_kbnode (kb1); xfree (ctrl); } - -int assert_signer_true = 0; - -void -check_assert_signer_list (const char *mainpkhex, const char *pkhex) -{ - (void)mainpkhex; - (void)pkhex; -} diff --git a/g10/t-keydb.c b/g10/t-keydb.c index 9055d5b94..4c78dac48 100644 --- a/g10/t-keydb.c +++ b/g10/t-keydb.c @@ -105,13 +105,3 @@ do_test (int argc, char *argv[]) keydb_release (hd2); xfree (ctrl); } - - -int assert_signer_true = 0; - -void -check_assert_signer_list (const char *mainpkhex, const char *pkhex) -{ - (void)mainpkhex; - (void)pkhex; -} diff --git a/g10/t-keyid.c b/g10/t-keyid.c new file mode 100644 index 000000000..d42399027 --- /dev/null +++ b/g10/t-keyid.c @@ -0,0 +1,129 @@ +/* t-keyid.c - Tests for keyid.c. + * Copyright (C) 2024 g10 Code GmbH + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuPG 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#define LEAN_T_SUPPORT 1 + +#define PGM "t-keyid" + +#include "gpg.h" +#include "keydb.h" +#include "../common/t-support.h" + + + +static int verbose; + + +static void +test_compare_pubkey_string (void) +{ + static struct { const char *astr; const char *bstr; int expected; } t[] = + { + { "rsa2048" , "rsa2048" , 1 }, + { "rsa2048" , ">=rsa2048" , 1 }, + { "rsa2048" , ">rsa2048" , 0 }, + { "ed25519" , ">rsa1024" , 0 }, + { "ed25519" , "ed25519" , 1 }, + { "ed25519" , ",,,=ed25519" , 1 }, + { "nistp384" , ">nistp256" , 1 }, + { "nistp521" , ">=rsa3072, >nistp384", 1 }, + { " nistp521" , ">=rsa3072, >nistp384 ", 1 }, + { " nistp521 " , " >=rsa3072, >nistp384 ", 1 }, + { " =nistp521 " , " >=rsa3072, >nistp384,,", 1 }, + { "nistp384" , ">nistp384" , 0 }, + { "nistp384" , ">=nistp384" , 1 }, + { "brainpoolP384" , ">=brainpoolp256", 1 }, + { "brainpoolP384" , ">brainpoolp384" , 0 }, + { "brainpoolP384" , ">=brainpoolp384", 1 }, + { "brainpoolP256r1", ">brainpoolp256r1", 0 }, + { "brainpoolP384r1", ">brainpoolp384r1" , 0 }, + { "brainpoolP384r1", ">=brainpoolp384r1", 1 }, + { "brainpoolP384r1", ">=brainpoolp384" , 1 }, + { "", "", 0} + }; + int idx; + int result; + + for (idx=0; idx < DIM(t); idx++) + { + result = compare_pubkey_string (t[idx].astr, t[idx].bstr); + if (result != t[idx].expected) + { + fail (idx); + if (verbose) + log_debug ("\"%s\", \"%s\" want %d got %d\n", + t[idx].astr, t[idx].bstr, t[idx].expected, result); + } + } + +} + + +int +main (int argc, char **argv) +{ + int last_argc = -1; + + no_exit_on_fail = 1; + + if (argc) + { argc--; argv++; } + while (argc && last_argc != argc ) + { + last_argc = argc; + if (!strcmp (*argv, "--")) + { + argc--; argv++; + break; + } + else if (!strcmp (*argv, "--help")) + { + fputs ("usage: " PGM " [FILE]\n" + "Options:\n" + " --verbose Print timings etc.\n" + " --debug Flyswatter\n" + , stdout); + exit (0); + } + else if (!strcmp (*argv, "--verbose")) + { + verbose++; + argc--; argv++; + } + else if (!strcmp (*argv, "--debug")) + { + verbose += 2; + argc--; argv++; + } + else if (!strncmp (*argv, "--", 2)) + { + fprintf (stderr, PGM ": unknown option '%s'\n", *argv); + exit (1); + } + } + + test_compare_pubkey_string (); + + return !!errcount; +} diff --git a/g10/t-stutter.c b/g10/t-stutter.c index 7b2ea4b37..503a92004 100644 --- a/g10/t-stutter.c +++ b/g10/t-stutter.c @@ -611,12 +611,3 @@ do_test (int argc, char *argv[]) xfree (filename); } - -int assert_signer_true = 0; - -void -check_assert_signer_list (const char *mainpkhex, const char *pkhex) -{ - (void)mainpkhex; - (void)pkhex; -} diff --git a/g10/test-stubs.c b/g10/test-stubs.c index 6ae0f4eb7..d9bead754 100644 --- a/g10/test-stubs.c +++ b/g10/test-stubs.c @@ -43,6 +43,9 @@ #include "call-agent.h" int g10_errors_seen; +int assert_signer_true = 0; +int assert_pubkey_algo_false = 0; + void @@ -580,3 +583,18 @@ impex_filter_getval (void *cookie, const char *propname) (void)propname; return NULL; } + + +void +check_assert_signer_list (const char *mainpkhex, const char *pkhex) +{ + (void)mainpkhex; + (void)pkhex; +} + +void +check_assert_pubkey_algo (const char *algostr, const char *pkhex) +{ + (void)algostr; + (void)pkhex; +} diff --git a/g10/test.c b/g10/test.c index 648148a10..f6c697a35 100644 --- a/g10/test.c +++ b/g10/test.c @@ -15,6 +15,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-3.0-or-later */ #include <config.h> diff --git a/g10/verify.c b/g10/verify.c index e9792939d..1c3de767c 100644 --- a/g10/verify.c +++ b/g10/verify.c @@ -333,7 +333,7 @@ check_assert_signer_list (const char *mainpkhex, const char *pkhex) assert_signer_true = 1; write_status_text (STATUS_ASSERT_SIGNER, item->d); if (!opt.quiet) - log_info ("signer '%s' matched\n", item->d); + log_info ("asserted signer '%s'\n", item->d); goto leave; } } @@ -388,7 +388,7 @@ check_assert_signer_list (const char *mainpkhex, const char *pkhex) assert_signer_true = 1; write_status_text (STATUS_ASSERT_SIGNER, p); if (!opt.quiet) - log_info ("signer '%s' matched '%s', line %d\n", + log_info ("asserted signer '%s' (%s:%d)\n", p, fname, lnr); goto leave; } @@ -405,3 +405,32 @@ check_assert_signer_list (const char *mainpkhex, const char *pkhex) leave: es_fclose (fp); } + + +/* This function shall be called with the signer's public key + * algorithm ALGOSTR iff a signature is fully valid. If the option + * --assert-pubkey-algo is active the functions checks whether the + * signing key's algo is valid according to that list; in this case a + * global flag is set. */ +void +check_assert_pubkey_algo (const char *algostr, const char *pkhex) +{ + if (!opt.assert_pubkey_algos) + return; /* Nothing to do. */ + + if (compare_pubkey_string (algostr, opt.assert_pubkey_algos)) + { + write_status_strings (STATUS_ASSERT_PUBKEY_ALGO, + pkhex, " 1 ", algostr, NULL); + if (!opt.quiet) + log_info ("asserted signer '%s' with algo %s\n", pkhex, algostr); + } + else + { + if (!opt.quiet) + log_info ("denied signer '%s' with algo %s\n", pkhex, algostr); + assert_pubkey_algo_false = 1; + write_status_strings (STATUS_ASSERT_PUBKEY_ALGO, + pkhex, " 0 ", algostr, NULL); + } +} |