aboutsummaryrefslogtreecommitdiffstats
path: root/g10
diff options
context:
space:
mode:
Diffstat (limited to 'g10')
-rw-r--r--g10/Makefile.am6
-rw-r--r--g10/build-packet.c4
-rw-r--r--g10/compress-bz2.c26
-rw-r--r--g10/compress.c28
-rw-r--r--g10/export.c9
-rw-r--r--g10/getkey.c2
-rw-r--r--g10/gpg.c56
-rw-r--r--g10/gpgv.c32
-rw-r--r--g10/import.c9
-rw-r--r--g10/key-clean.c41
-rw-r--r--g10/key-clean.h5
-rw-r--r--g10/keydb.h2
-rw-r--r--g10/keyedit.c16
-rw-r--r--g10/keyid.c178
-rw-r--r--g10/main.h2
-rw-r--r--g10/mainproc.c21
-rw-r--r--g10/options.h15
-rw-r--r--g10/t-keydb-get-keyblock.c9
-rw-r--r--g10/t-keydb.c10
-rw-r--r--g10/t-keyid.c129
-rw-r--r--g10/t-stutter.c9
-rw-r--r--g10/tdbdump.c6
-rw-r--r--g10/tdbio.c16
-rw-r--r--g10/tdbio.h3
-rw-r--r--g10/test-stubs.c18
-rw-r--r--g10/test.c1
-rw-r--r--g10/trustdb.c110
-rw-r--r--g10/verify.c33
28 files changed, 619 insertions, 177 deletions
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
diff --git a/g10/build-packet.c b/g10/build-packet.c
index 67d4a6eef..19a13760a 100644
--- a/g10/build-packet.c
+++ b/g10/build-packet.c
@@ -306,7 +306,9 @@ gpg_mpi_write (iobuf_t out, gcry_mpi_t a, unsigned int *r_nwritten)
p = gcry_mpi_get_opaque (a, &nbits);
if (p)
{
- /* Strip leading zero bits. */
+ /* First get nbits back to full bytes. */
+ nbits = ((nbits + 7) / 8) * 8;
+ /* Then strip leading zero bits. */
for (; nbits >= 8 && !*p; p++, nbits -= 8)
;
if (nbits >= 8 && !(*p & 0x80))
diff --git a/g10/compress-bz2.c b/g10/compress-bz2.c
index 2c3b86f8f..162dee96e 100644
--- a/g10/compress-bz2.c
+++ b/g10/compress-bz2.c
@@ -53,7 +53,11 @@ init_compress( compress_filter_context_t *zfx, bz_stream *bzs )
}
if((rc=BZ2_bzCompressInit(bzs,level,0,0))!=BZ_OK)
- log_fatal("bz2lib problem: %d\n",rc);
+ {
+ log_error ("bz2lib problem: %d\n",rc);
+ write_status_error ("bzip2.init", gpg_error (GPG_ERR_INTERNAL));
+ g10_exit (2);
+ }
zfx->outbufsize = 8192;
zfx->outbuf = xmalloc( zfx->outbufsize );
@@ -80,7 +84,11 @@ do_compress(compress_filter_context_t *zfx, bz_stream *bzs, int flush, IOBUF a)
if( zrc == BZ_STREAM_END && flush == BZ_FINISH )
;
else if( zrc != BZ_RUN_OK && zrc != BZ_FINISH_OK )
- log_fatal("bz2lib deflate problem: rc=%d\n", zrc );
+ {
+ log_error ("bz2lib deflate problem: rc=%d\n", zrc );
+ write_status_error ("bzip2.deflate", gpg_error (GPG_ERR_INTERNAL));
+ g10_exit (2);
+ }
n = zfx->outbufsize - bzs->avail_out;
if( DBG_FILTER )
@@ -91,7 +99,7 @@ do_compress(compress_filter_context_t *zfx, bz_stream *bzs, int flush, IOBUF a)
if( (rc=iobuf_write( a, zfx->outbuf, n )) )
{
- log_debug("bzCompress: iobuf_write failed\n");
+ log_error ("bzCompress: iobuf_write failed\n");
return rc;
}
}
@@ -106,7 +114,11 @@ init_uncompress( compress_filter_context_t *zfx, bz_stream *bzs )
int rc;
if((rc=BZ2_bzDecompressInit(bzs,0,opt.bz2_decompress_lowmem))!=BZ_OK)
- log_fatal("bz2lib problem: %d\n",rc);
+ {
+ log_error ("bz2lib problem: %d\n",rc);
+ write_status_error ("bzip2.init.un", gpg_error (GPG_ERR_INTERNAL));
+ g10_exit (2);
+ }
zfx->inbufsize = 2048;
zfx->inbuf = xmalloc( zfx->inbufsize );
@@ -159,7 +171,11 @@ do_uncompress( compress_filter_context_t *zfx, bz_stream *bzs,
if( zrc == BZ_STREAM_END )
rc = -1; /* eof */
else if( zrc != BZ_OK && zrc != BZ_PARAM_ERROR )
- log_fatal("bz2lib inflate problem: rc=%d\n", zrc );
+ {
+ log_error ("bz2lib inflate problem: rc=%d\n", zrc );
+ write_status_error ("bzip2.inflate", gpg_error (GPG_ERR_BAD_DATA));
+ g10_exit (2);
+ }
else if (zrc == BZ_OK && eofseen
&& !bzs->avail_in && bzs->avail_out > 0)
{
diff --git a/g10/compress.c b/g10/compress.c
index 9e094460f..e787b2918 100644
--- a/g10/compress.c
+++ b/g10/compress.c
@@ -73,10 +73,12 @@ init_compress( compress_filter_context_t *zfx, z_stream *zs )
-13, 8, Z_DEFAULT_STRATEGY)
: deflateInit( zs, level )
) != Z_OK ) {
- log_fatal("zlib problem: %s\n", zs->msg? zs->msg :
+ log_error ("zlib problem: %s\n", zs->msg? zs->msg :
rc == Z_MEM_ERROR ? "out of core" :
rc == Z_VERSION_ERROR ? "invalid lib version" :
"unknown error" );
+ write_status_error ("zlib.init", gpg_error (GPG_ERR_INTERNAL));
+ g10_exit (2);
}
zfx->outbufsize = 8192;
@@ -104,9 +106,11 @@ do_compress( compress_filter_context_t *zfx, z_stream *zs, int flush, IOBUF a )
;
else if( zrc != Z_OK ) {
if( zs->msg )
- log_fatal("zlib deflate problem: %s\n", zs->msg );
+ log_error ("zlib deflate problem: %s\n", zs->msg );
else
- log_fatal("zlib deflate problem: rc=%d\n", zrc );
+ log_error ("zlib deflate problem: rc=%d\n", zrc );
+ write_status_error ("zlib.deflate", gpg_error (GPG_ERR_INTERNAL));
+ g10_exit (2);
}
n = zfx->outbufsize - zs->avail_out;
if( DBG_FILTER )
@@ -116,7 +120,7 @@ do_compress( compress_filter_context_t *zfx, z_stream *zs, int flush, IOBUF a )
(unsigned)n, zrc );
if( (rc=iobuf_write( a, zfx->outbuf, n )) ) {
- log_debug("deflate: iobuf_write failed\n");
+ log_error ("deflate: iobuf_write failed\n");
return rc;
}
} while( zs->avail_in || (flush == Z_FINISH && zrc != Z_STREAM_END) );
@@ -140,10 +144,12 @@ init_uncompress( compress_filter_context_t *zfx, z_stream *zs )
*/
if( (rc = zfx->algo == 1? inflateInit2( zs, -15)
: inflateInit( zs )) != Z_OK ) {
- log_fatal("zlib problem: %s\n", zs->msg? zs->msg :
- rc == Z_MEM_ERROR ? "out of core" :
- rc == Z_VERSION_ERROR ? "invalid lib version" :
- "unknown error" );
+ log_error ("zlib problem: %s\n", zs->msg? zs->msg :
+ rc == Z_MEM_ERROR ? "out of core" :
+ rc == Z_VERSION_ERROR ? "invalid lib version" :
+ "unknown error" );
+ write_status_error ("zlib.init.un", gpg_error (GPG_ERR_INTERNAL));
+ g10_exit (2);
}
zfx->inbufsize = 2048;
@@ -198,9 +204,11 @@ do_uncompress( compress_filter_context_t *zfx, z_stream *zs,
rc = -1; /* eof */
else if( zrc != Z_OK && zrc != Z_BUF_ERROR ) {
if( zs->msg )
- log_fatal("zlib inflate problem: %s\n", zs->msg );
+ log_error ("zlib inflate problem: %s\n", zs->msg );
else
- log_fatal("zlib inflate problem: rc=%d\n", zrc );
+ log_error ("zlib inflate problem: rc=%d\n", zrc );
+ write_status_error ("zlib.inflate", gpg_error (GPG_ERR_BAD_DATA));
+ g10_exit (2);
}
} while (zs->avail_out && zrc != Z_STREAM_END && zrc != Z_BUF_ERROR
&& !leave);
diff --git a/g10/export.c b/g10/export.c
index 2c6eb7bff..74cb03764 100644
--- a/g10/export.c
+++ b/g10/export.c
@@ -129,6 +129,8 @@ parse_export_options(char *str,unsigned int *options,int noisy)
N_("export revocation keys marked as \"sensitive\"")},
{"export-clean",EXPORT_CLEAN,NULL,
N_("remove unusable parts from key during export")},
+ {"export-realclean",EXPORT_MINIMAL|EXPORT_REALCLEAN|EXPORT_CLEAN,NULL,
+ NULL},
{"export-minimal",EXPORT_MINIMAL|EXPORT_CLEAN,NULL,
N_("remove as much as possible from key during export")},
@@ -166,7 +168,7 @@ parse_export_options(char *str,unsigned int *options,int noisy)
{
*options |= (EXPORT_LOCAL_SIGS | EXPORT_ATTRIBUTES
| EXPORT_SENSITIVE_REVKEYS);
- *options &= ~(EXPORT_CLEAN | EXPORT_MINIMAL
+ *options &= ~(EXPORT_CLEAN | EXPORT_MINIMAL | EXPORT_REALCLEAN
| EXPORT_DANE_FORMAT);
}
@@ -643,7 +645,7 @@ canon_pk_algo (enum gcry_pk_algos algo)
}
-/* Take an s-expression wit the public and private key and change the
+/* Take an s-expression with the public and private key and change the
* parameter array in PK to include the secret parameters. */
static gpg_error_t
secret_key_to_mode1003 (gcry_sexp_t s_key, PKT_public_key *pk)
@@ -2366,8 +2368,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
if ((options & EXPORT_CLEAN))
{
merge_keys_and_selfsig (ctrl, keyblock);
- clean_all_uids (ctrl, keyblock, opt.verbose,
- (options&EXPORT_MINIMAL), NULL, NULL);
+ clean_all_uids (ctrl, keyblock, opt.verbose, options, NULL, NULL);
clean_all_subkeys (ctrl, keyblock, opt.verbose,
(options&EXPORT_MINIMAL)? KEY_CLEAN_ALL
/**/ : KEY_CLEAN_AUTHENCR,
diff --git a/g10/getkey.c b/g10/getkey.c
index b959d77c7..ce59628a0 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -1921,7 +1921,7 @@ get_pubkey_byfprint_fast (ctrl_t ctrl, PKT_public_key * pk,
* R_HD may be NULL. If LOCK is set the handle has been opend in
* locked mode and keydb_disable_caching () has been called. On error
* R_KEYBLOCK is set to NULL but R_HD must be released by the caller;
- * it may have a value of NULL, though. This allows to do an insert
+ * it may have a value of NULL, though. This allows one to do an insert
* operation on a locked keydb handle. */
gpg_error_t
get_keyblock_byfprint_fast (ctrl_t ctrl,
diff --git a/g10/gpg.c b/g10/gpg.c
index 96a0c345c..bef3b6fbd 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -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")),
@@ -753,7 +755,7 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_s_n (oNoEscapeFrom, "no-escape-from-lines", "@"),
ARGPARSE_s_n (oMimemode, "mimemode", "@"),
ARGPARSE_s_n (oTextmodeShort, NULL, "@"),
- ARGPARSE_s_n (oTextmode, "textmode", N_("use canonical text mode")),
+ ARGPARSE_s_n (oTextmode, "textmode", "@"),
ARGPARSE_s_n (oNoTextmode, "no-textmode", "@"),
ARGPARSE_s_s (oSetFilename, "set-filename", "@"),
ARGPARSE_s_n (oForYourEyesOnly, "for-your-eyes-only", "@"),
@@ -1045,9 +1047,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 =
@@ -3584,9 +3589,18 @@ main (int argc, char **argv)
case oPersonalCompressPreferences:
pers_compress_list=pargs.r.ret_str;
break;
- case oAgentProgram: opt.agent_program = pargs.r.ret_str; break;
- case oKeyboxdProgram: opt.keyboxd_program = pargs.r.ret_str; break;
- case oDirmngrProgram: opt.dirmngr_program = pargs.r.ret_str; break;
+ case oAgentProgram:
+ xfree (opt.agent_program);
+ opt.agent_program = make_filename (pargs.r.ret_str, NULL);
+ break;
+ case oKeyboxdProgram:
+ xfree (opt.keyboxd_program);
+ opt.keyboxd_program = make_filename (pargs.r.ret_str, NULL);
+ break;
+ case oDirmngrProgram:
+ xfree (opt.dirmngr_program);
+ opt.dirmngr_program = make_filename (pargs.r.ret_str, NULL);
+ break;
case oDisableDirmngr: opt.disable_dirmngr = 1; break;
case oWeakDigest:
additional_weak_digest(pargs.r.ret_str);
@@ -3767,6 +3781,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;
@@ -5471,6 +5497,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. */
@@ -5495,15 +5532,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/import.c b/g10/import.c
index 8f874a7d1..ff8847cb6 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -2081,7 +2081,9 @@ import_one_real (ctrl_t ctrl,
{
merge_keys_and_selfsig (ctrl, keyblock);
clean_all_uids (ctrl, keyblock,
- opt.verbose, (options&IMPORT_MINIMAL), NULL, NULL);
+ opt.verbose,
+ (options&IMPORT_MINIMAL)? EXPORT_MINIMAL : 0,
+ NULL, NULL);
clean_all_subkeys (ctrl, keyblock, opt.verbose, KEY_CLEAN_NONE,
NULL, NULL);
}
@@ -2233,7 +2235,8 @@ import_one_real (ctrl_t ctrl,
if ((options & IMPORT_CLEAN))
{
merge_keys_and_selfsig (ctrl, keyblock);
- clean_all_uids (ctrl, keyblock, opt.verbose, (options&IMPORT_MINIMAL),
+ clean_all_uids (ctrl, keyblock, opt.verbose,
+ (options&IMPORT_MINIMAL)? EXPORT_MINIMAL : 0,
&n_uids_cleaned,&n_sigs_cleaned);
clean_all_subkeys (ctrl, keyblock, opt.verbose, KEY_CLEAN_NONE,
NULL, NULL);
@@ -2331,7 +2334,7 @@ import_one_real (ctrl_t ctrl,
{
merge_keys_and_selfsig (ctrl, keyblock_orig);
clean_all_uids (ctrl, keyblock_orig, opt.verbose,
- (options&IMPORT_MINIMAL),
+ (options&IMPORT_MINIMAL)? EXPORT_MINIMAL : 0,
&n_uids_cleaned,&n_sigs_cleaned);
clean_all_subkeys (ctrl, keyblock_orig, opt.verbose, KEY_CLEAN_NONE,
NULL, NULL);
diff --git a/g10/key-clean.c b/g10/key-clean.c
index c8a6efe50..ca8ca40d9 100644
--- a/g10/key-clean.c
+++ b/g10/key-clean.c
@@ -91,6 +91,7 @@ mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
continue;
}
node->flag |= 1<<NF_CONSIDER;
+
}
/* Reset the remaining flags. */
for (; node; node = node->next)
@@ -215,9 +216,22 @@ mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
}
+/* Return true if the signature at NODE has is from a key specified by
+ * the --trusted-key option and is exportable. */
+static int
+is_trusted_key_sig (kbnode_t node)
+{
+ if (!node->pkt->pkt.signature->flags.exportable)
+ return 0;
+ /* Not yet implemented. */
+ return 0;
+}
+
+
+/* Note: OPTIONS are from the EXPORT_* set. */
static int
clean_sigs_from_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
- int noisy, int self_only)
+ int noisy, unsigned int options)
{
int deleted = 0;
kbnode_t node;
@@ -256,8 +270,15 @@ clean_sigs_from_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
{
int keep;
- keep = self_only? (node->pkt->pkt.signature->keyid[0] == keyid[0]
- && node->pkt->pkt.signature->keyid[1] == keyid[1]) : 1;
+ if ((options & EXPORT_REALCLEAN))
+ keep = ((node->pkt->pkt.signature->keyid[0] == keyid[0]
+ && node->pkt->pkt.signature->keyid[1] == keyid[1])
+ || is_trusted_key_sig (node));
+ else if ((options & EXPORT_MINIMAL))
+ keep = (node->pkt->pkt.signature->keyid[0] == keyid[0]
+ && node->pkt->pkt.signature->keyid[1] == keyid[1]);
+ else
+ keep = 1;
/* Keep usable uid sigs ... */
if ((node->flag & (1<<NF_USABLE)) && keep)
@@ -364,10 +385,12 @@ clean_uid_from_key (kbnode_t keyblock, kbnode_t uidnode, int noisy)
}
-/* Needs to be called after a merge_keys_and_selfsig() */
+/* Needs to be called after a merge_keys_and_selfsig().
+ * Note: OPTIONS are from the EXPORT_* set. */
void
clean_one_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
- int noisy, int self_only, int *uids_cleaned, int *sigs_cleaned)
+ int noisy, unsigned int options,
+ int *uids_cleaned, int *sigs_cleaned)
{
int dummy = 0;
@@ -386,15 +409,15 @@ clean_one_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
*uids_cleaned += clean_uid_from_key (keyblock, uidnode, noisy);
if (!uidnode->pkt->pkt.user_id->flags.compacted)
*sigs_cleaned += clean_sigs_from_uid (ctrl, keyblock, uidnode,
- noisy, self_only);
+ noisy, options);
}
/* NB: This function marks the deleted nodes only and the caller is
* responsible to skip or remove them. Needs to be called after a
- * merge_keys_and_selfsig(). */
+ * merge_keys_and_selfsig. Note: OPTIONS are from the EXPORT_* set. */
void
-clean_all_uids (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only,
+clean_all_uids (ctrl_t ctrl, kbnode_t keyblock, int noisy, unsigned int options,
int *uids_cleaned, int *sigs_cleaned)
{
kbnode_t node;
@@ -405,7 +428,7 @@ clean_all_uids (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only,
node = node->next)
{
if (node->pkt->pkttype == PKT_USER_ID)
- clean_one_uid (ctrl, keyblock, node, noisy, self_only,
+ clean_one_uid (ctrl, keyblock, node, noisy, options,
uids_cleaned, sigs_cleaned);
}
diff --git a/g10/key-clean.h b/g10/key-clean.h
index c4f164928..b2825b0c5 100644
--- a/g10/key-clean.h
+++ b/g10/key-clean.h
@@ -40,9 +40,10 @@ void mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
u32 curtime, u32 *next_expire);
void clean_one_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
- int noisy, int self_only,
+ int noisy, unsigned int options,
int *uids_cleaned, int *sigs_cleaned);
-void clean_all_uids (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only,
+void clean_all_uids (ctrl_t ctrl, kbnode_t keyblock,
+ int noisy, unsigned int options,
int *uids_cleaned,int *sigs_cleaned);
void clean_all_subkeys (ctrl_t ctrl, kbnode_t keyblock,
int noisy, int clean_level,
diff --git a/g10/keydb.h b/g10/keydb.h
index b18f6e93a..62a99295d 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 );
@@ -572,6 +573,7 @@ const char *colon_expirestr_from_sig (PKT_signature *sig);
byte *fingerprint_from_pk( PKT_public_key *pk, byte *buf, size_t *ret_len );
byte *v5_fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len);
void fpr20_from_pk (PKT_public_key *pk, byte array[20]);
+void fpr20_from_fpr (const byte *fpr, unsigned int fprlen, byte array[20]);
char *hexfingerprint (PKT_public_key *pk, char *buffer, size_t buflen);
char *v5hexfingerprint (PKT_public_key *pk, char *buffer, size_t buflen);
char *format_hexfingerprint (const char *fingerprint,
diff --git a/g10/keyedit.c b/g10/keyedit.c
index e56e6d10b..7523a1a62 100644
--- a/g10/keyedit.c
+++ b/g10/keyedit.c
@@ -70,7 +70,7 @@ static int menu_adduid (ctrl_t ctrl, kbnode_t keyblock,
int photo, const char *photo_name, const char *uidstr);
static void menu_deluid (KBNODE pub_keyblock);
static int menu_delsig (ctrl_t ctrl, kbnode_t pub_keyblock);
-static int menu_clean (ctrl_t ctrl, kbnode_t keyblock, int self_only);
+static int menu_clean (ctrl_t ctrl, kbnode_t keyblock, unsigned int options);
static void menu_delkey (KBNODE pub_keyblock);
static int menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive);
static int menu_addadsk (ctrl_t ctrl, kbnode_t pub_keyblock,
@@ -2258,7 +2258,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
break;
case cmdMINIMIZE:
- if (menu_clean (ctrl, keyblock, 1))
+ if (menu_clean (ctrl, keyblock, EXPORT_MINIMAL))
redisplay = modified = 1;
break;
@@ -4543,11 +4543,13 @@ menu_delsig (ctrl_t ctrl, kbnode_t pub_keyblock)
}
+/* Note: OPTIONS are from the EXPORT_* set. */
static int
-menu_clean (ctrl_t ctrl, kbnode_t keyblock, int self_only)
+menu_clean (ctrl_t ctrl, kbnode_t keyblock, unsigned int options)
{
KBNODE uidnode;
- int modified = 0, select_all = !count_selected_uids (keyblock);
+ int modified = 0;
+ int select_all = !count_selected_uids (keyblock);
for (uidnode = keyblock->next;
uidnode && uidnode->pkt->pkttype != PKT_PUBLIC_SUBKEY;
@@ -4561,8 +4563,8 @@ menu_clean (ctrl_t ctrl, kbnode_t keyblock, int self_only)
uidnode->pkt->pkt.user_id->len,
0);
- clean_one_uid (ctrl, keyblock, uidnode, opt.verbose, self_only, &uids,
- &sigs);
+ clean_one_uid (ctrl, keyblock, uidnode, opt.verbose, options,
+ &uids, &sigs);
if (uids)
{
const char *reason;
@@ -4587,7 +4589,7 @@ menu_clean (ctrl_t ctrl, kbnode_t keyblock, int self_only)
}
else
{
- tty_printf (self_only == 1 ?
+ tty_printf ((options & EXPORT_MINIMAL)?
_("User ID \"%s\": already minimized\n") :
_("User ID \"%s\": already clean\n"), user);
}
diff --git a/g10/keyid.c b/g10/keyid.c
index ed76818a2..7e4c50b59 100644
--- a/g10/keyid.c
+++ b/g10/keyid.c
@@ -145,6 +145,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. */
@@ -239,20 +363,16 @@ do_hash_public_key (gcry_md_hd_t md, PKT_public_key *pk, int use_v5)
if (use_v5)
{
gcry_md_putc ( md, 0x9a ); /* ctb */
- gcry_md_putc ( md, n >> 24 ); /* 4 byte length header */
+ gcry_md_putc ( md, n >> 24 ); /* 4 byte length header (upper bits) */
gcry_md_putc ( md, n >> 16 );
- gcry_md_putc ( md, n >> 8 );
- gcry_md_putc ( md, n );
- /* Note that the next byte may either be 4 or 5. */
- gcry_md_putc ( md, pk->version );
}
else
{
gcry_md_putc ( md, 0x99 ); /* ctb */
- gcry_md_putc ( md, n >> 8 ); /* 2 byte length header */
- gcry_md_putc ( md, n );
- gcry_md_putc ( md, pk->version );
}
+ gcry_md_putc ( md, n >> 8 ); /* lower bits of the length header. */
+ gcry_md_putc ( md, n );
+ gcry_md_putc ( md, pk->version );
gcry_md_putc ( md, pk->timestamp >> 24 );
gcry_md_putc ( md, pk->timestamp >> 16 );
gcry_md_putc ( md, pk->timestamp >> 8 );
@@ -260,7 +380,7 @@ do_hash_public_key (gcry_md_hd_t md, PKT_public_key *pk, int use_v5)
gcry_md_putc ( md, pk->pubkey_algo );
- if (use_v5)
+ if (use_v5) /* Hash the 32 bit length */
{
n -= 10;
gcry_md_putc ( md, n >> 24 );
@@ -936,6 +1056,32 @@ v5_fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len)
/*
+ * This is the core of fpr20_from_pk which directly takes a
+ * fingerprint and its length instead of the public key. See below
+ * for details.
+ */
+void
+fpr20_from_fpr (const byte *fpr, unsigned int fprlen, byte array[20])
+{
+ if (fprlen >= 32) /* v5 fingerprint (or larger) */
+ {
+ memcpy (array + 0, fpr + 20, 4);
+ memcpy (array + 4, fpr + 24, 4);
+ memcpy (array + 8, fpr + 28, 4);
+ memcpy (array + 12, fpr + 0, 4); /* kid[0] */
+ memcpy (array + 16, fpr + 4, 4); /* kid[1] */
+ }
+ else if (fprlen == 20) /* v4 fingerprint */
+ memcpy (array, fpr, 20);
+ else /* v3 or too short: fill up with zeroes. */
+ {
+ memset (array, 0, 20);
+ memcpy (array, fpr, fprlen);
+ }
+}
+
+
+/*
* Get FPR20 for the given PK/SK into ARRAY.
*
* FPR20 is special form of fingerprint of length 20 for the record of
@@ -951,19 +1097,7 @@ fpr20_from_pk (PKT_public_key *pk, byte array[20])
if (!pk->fprlen)
compute_fingerprint (pk);
- if (!array)
- array = xmalloc (pk->fprlen);
-
- if (pk->fprlen == 32) /* v5 fingerprint */
- {
- memcpy (array + 0, pk->fpr + 20, 4);
- memcpy (array + 4, pk->fpr + 24, 4);
- memcpy (array + 8, pk->fpr + 28, 4);
- memcpy (array + 12, pk->fpr + 0, 4); /* kid[0] */
- memcpy (array + 16, pk->fpr + 4, 4); /* kid[1] */
- }
- else /* v4 fingerprint */
- memcpy (array, pk->fpr, 20);
+ fpr20_from_fpr (pk->fpr, pk->fprlen, array);
}
diff --git a/g10/main.h b/g10/main.h
index c202dacb8..5123dd03b 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__));
@@ -495,6 +496,7 @@ int verify_files (ctrl_t ctrl, int nfiles, char **files );
int gpg_verify (ctrl_t ctrl, gnupg_fd_t sig_fd, gnupg_fd_t 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 74c7430ec..043b34f62 100644
--- a/g10/mainproc.c
+++ b/g10/mainproc.c
@@ -898,7 +898,7 @@ proc_encrypted (CTX c, PACKET *pkt)
* encrypted packet. */
literals_seen++;
- /* The --require-compliance option allows to simplify decryption in
+ /* The --require-compliance option allows one to simplify decryption in
* de-vs compliance mode by just looking at the exit status. */
if (opt.flags.require_compliance
&& opt.compliance == CO_DE_VS
@@ -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 571399967..476c30ad5 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -126,9 +126,9 @@ struct
int marginals_needed;
int completes_needed;
int max_cert_depth;
- const char *agent_program;
- const char *keyboxd_program;
- const char *dirmngr_program;
+ char *agent_program;
+ char *keyboxd_program;
+ char *dirmngr_program;
int disable_dirmngr;
const char *def_new_key_algo;
@@ -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
@@ -414,12 +418,13 @@ EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode;
#define EXPORT_ATTRIBUTES (1<<1)
#define EXPORT_SENSITIVE_REVKEYS (1<<2)
#define EXPORT_RESET_SUBKEY_PASSWD (1<<3)
-#define EXPORT_MINIMAL (1<<4)
-#define EXPORT_CLEAN (1<<5)
+#define EXPORT_MINIMAL (1<<5)
+#define EXPORT_CLEAN (1<<6)
#define EXPORT_DANE_FORMAT (1<<7)
#define EXPORT_BACKUP (1<<10)
#define EXPORT_REVOCS (1<<11)
#define EXPORT_MODE1003 (1<<12)
+#define EXPORT_REALCLEAN (1<<13)
#define LIST_SHOW_PHOTOS (1<<0)
#define LIST_SHOW_POLICY_URLS (1<<1)
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/tdbdump.c b/g10/tdbdump.c
index 9ff3f81a3..99f135678 100644
--- a/g10/tdbdump.c
+++ b/g10/tdbdump.c
@@ -190,7 +190,11 @@ import_ownertrust (ctrl_t ctrl, const char *fname )
while (fprlen < MAX_FINGERPRINT_LEN)
fpr[fprlen++] = 0;
- rc = tdbio_search_trust_byfpr (ctrl, fpr, &rec);
+ /* FIXME: The intention is to save the special fpr20 as used
+ * in the trustdb here. However, the above conversions seems
+ * not to be aware of this. Or why does it allow up to
+ * MAX_FINGERPRINT_LEN ? */
+ rc = tdbio_search_trust_byfpr (ctrl, fpr, 20, &rec);
if( !rc ) { /* found: update */
if (rec.r.trust.ownertrust != otrust)
{
diff --git a/g10/tdbio.c b/g10/tdbio.c
index 1b68f772f..7ee62fca0 100644
--- a/g10/tdbio.c
+++ b/g10/tdbio.c
@@ -1864,13 +1864,21 @@ cmp_trec_fpr ( const void *fpr, const TRUSTREC *rec )
* Return: 0 if found, GPG_ERR_NOT_FOUND, or another error code.
*/
gpg_error_t
-tdbio_search_trust_byfpr (ctrl_t ctrl, const byte *fingerprint, TRUSTREC *rec)
+tdbio_search_trust_byfpr (ctrl_t ctrl, const byte *fpr, unsigned int fprlen,
+ TRUSTREC *rec)
{
int rc;
+ byte fingerprint[20];
+
+ if (fprlen != 20)
+ {
+ fpr20_from_fpr (fpr, fprlen, fingerprint);
+ fpr = fingerprint;
+ }
/* Locate the trust record using the hash table */
- rc = lookup_hashtable (get_trusthashrec (ctrl), fingerprint, 20,
- cmp_trec_fpr, fingerprint, rec );
+ rc = lookup_hashtable (get_trusthashrec (ctrl), fpr, 20,
+ cmp_trec_fpr, fpr, rec);
return rc;
}
@@ -1887,7 +1895,7 @@ tdbio_search_trust_bypk (ctrl_t ctrl, PKT_public_key *pk, TRUSTREC *rec)
byte fingerprint[20];
fpr20_from_pk (pk, fingerprint);
- return tdbio_search_trust_byfpr (ctrl, fingerprint, rec);
+ return tdbio_search_trust_byfpr (ctrl, fingerprint, 20, rec);
}
diff --git a/g10/tdbio.h b/g10/tdbio.h
index 9452d76c9..7cf630121 100644
--- a/g10/tdbio.h
+++ b/g10/tdbio.h
@@ -111,7 +111,8 @@ int tdbio_end_transaction(void);
int tdbio_cancel_transaction(void);
int tdbio_delete_record (ctrl_t ctrl, ulong recnum);
ulong tdbio_new_recnum (ctrl_t ctrl);
-gpg_error_t tdbio_search_trust_byfpr (ctrl_t ctrl, const byte *fingerprint,
+gpg_error_t tdbio_search_trust_byfpr (ctrl_t ctrl,
+ const byte *fpr, unsigned int fprlen,
TRUSTREC *rec);
gpg_error_t tdbio_search_trust_bypk (ctrl_t ctrl, PKT_public_key *pk,
TRUSTREC *rec);
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/trustdb.c b/g10/trustdb.c
index e846abe82..6de9f6b66 100644
--- a/g10/trustdb.c
+++ b/g10/trustdb.c
@@ -39,8 +39,52 @@
#include "tofu.h"
#include "key-clean.h"
+
+
+typedef struct key_item **KeyHashTable; /* see new_key_hash_table() */
+
+/*
+ * Structure to keep track of keys, this is used as an array where the
+ * item right after the last one has a keyblock set to NULL. Maybe we
+ * can drop this thing and replace it by key_item
+ */
+struct key_array
+{
+ KBNODE keyblock;
+};
+
+
+/* Control information for the trust DB. */
+static struct
+{
+ int init;
+ int level;
+ char *dbname;
+ int no_trustdb;
+} trustdb_args;
+
+
+/* Some globals. */
+static struct key_item *utk_list; /* all ultimately trusted keys */
+
+/* A list used to temporary store trusted keys and a flag indicated
+ * whether any --trusted-key option has been seen. */
+static struct key_item *trusted_key_list;
+static int any_trusted_key_seen;
+
+/* Flag whether a trustdb check is pending. */
+static int pending_check_trustdb;
+
+
+
static void write_record (ctrl_t ctrl, TRUSTREC *rec);
-static void do_sync(void);
+static void do_sync (void);
+static int validate_keys (ctrl_t ctrl, int interactive);
+
+
+/**********************************************
+ ************* some helpers *******************
+ **********************************************/
@@ -54,7 +98,7 @@ keyid_from_fpr20 (ctrl_t ctrl, const byte *fpr, u32 *keyid)
keyid = dummy_keyid;
/* Problem: We do only use fingerprints in the trustdb but
- * we need the keyID here to indetify the key; we can only
+ * we need the keyID here to identify the key; we can only
* use that ugly hack to distinguish between 16 and 20
* bytes fpr - it does not work always so we better change
* the whole validation code to only work with
@@ -88,40 +132,6 @@ keyid_from_fpr20 (ctrl_t ctrl, const byte *fpr, u32 *keyid)
return keyid[1];
}
-typedef struct key_item **KeyHashTable; /* see new_key_hash_table() */
-
-/*
- * Structure to keep track of keys, this is used as an array wherre
- * the item right after the last one has a keyblock set to NULL.
- * Maybe we can drop this thing and replace it by key_item
- */
-struct key_array
-{
- KBNODE keyblock;
-};
-
-
-/* Control information for the trust DB. */
-static struct
-{
- int init;
- int level;
- char *dbname;
- int no_trustdb;
-} trustdb_args;
-
-/* Some globals. */
-static struct key_item *user_utk_list; /* temp. used to store --trusted-keys */
-static struct key_item *utk_list; /* all ultimately trusted keys */
-
-static int pending_check_trustdb;
-
-static int validate_keys (ctrl_t ctrl, int interactive);
-
-
-/**********************************************
- ************* some helpers *******************
- **********************************************/
static struct key_item *
new_key_item (void)
@@ -245,11 +255,19 @@ tdb_register_trusted_keyid (u32 *keyid)
k = new_key_item ();
k->kid[0] = keyid[0];
k->kid[1] = keyid[1];
- k->next = user_utk_list;
- user_utk_list = k;
+ k->next = trusted_key_list;
+ trusted_key_list = k;
}
+/* This is called for the option --trusted-key to register these keys
+ * for later syncing them into the trustdb. The special value "none"
+ * may be used to indicate that there is a trusted-key option but no
+ * key shall be inserted for it. This "none" value is helpful to
+ * distinguish between changing the gpg.conf from a trusted-key to no
+ * trusted-key options at all. Simply not specify the option would
+ * not allow to distinguish this case from the --no-options case as
+ * used for certain calls of gpg for example by gpg-wks-client. */
void
tdb_register_trusted_key (const char *string)
{
@@ -257,6 +275,9 @@ tdb_register_trusted_key (const char *string)
KEYDB_SEARCH_DESC desc;
u32 kid[2];
+ any_trusted_key_seen = 1;
+ if (!strcmp (string, "none"))
+ return;
err = classify_user_id (string, &desc, 1);
if (!err)
{
@@ -378,11 +399,12 @@ verify_own_keys (ctrl_t ctrl)
if (!add_utk (kid))
log_info (_("key %s occurs more than once in the trustdb\n"),
keystr(kid));
- else if ((rec.r.trust.flags & 1))
+ else if ((rec.r.trust.flags & 1)
+ && any_trusted_key_seen)
{
/* Record marked as inserted via --trusted-key. Is this
* still the case? */
- for (k2 = user_utk_list; k2; k2 = k2->next)
+ for (k2 = trusted_key_list; k2; k2 = k2->next)
if (k2->kid[0] == kid[0] && k2->kid[1] == kid[1])
break;
if (!k2) /* No - clear the flag. */
@@ -406,7 +428,7 @@ verify_own_keys (ctrl_t ctrl)
}
/* Put any --trusted-key keys into the trustdb */
- for (k = user_utk_list; k; k = k->next)
+ for (k = trusted_key_list; k; k = k->next)
{
if ( add_utk (k->kid) )
{ /* not yet in trustDB as ultimately trusted */
@@ -431,9 +453,9 @@ verify_own_keys (ctrl_t ctrl)
}
}
- /* release the helper table table */
- release_key_items (user_utk_list);
- user_utk_list = NULL;
+ /* Release the helper table. */
+ release_key_items (trusted_key_list);
+ trusted_key_list = NULL;
return;
}
diff --git a/g10/verify.c b/g10/verify.c
index f8abadd45..c2c63255c 100644
--- a/g10/verify.c
+++ b/g10/verify.c
@@ -335,7 +335,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;
}
}
@@ -390,7 +390,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;
}
@@ -407,3 +407,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);
+ }
+}