diff options
Diffstat (limited to 'g10')
-rw-r--r-- | g10/Makefile.am | 6 | ||||
-rw-r--r-- | g10/build-packet.c | 4 | ||||
-rw-r--r-- | g10/compress-bz2.c | 26 | ||||
-rw-r--r-- | g10/compress.c | 28 | ||||
-rw-r--r-- | g10/export.c | 9 | ||||
-rw-r--r-- | g10/getkey.c | 2 | ||||
-rw-r--r-- | g10/gpg.c | 56 | ||||
-rw-r--r-- | g10/gpgv.c | 32 | ||||
-rw-r--r-- | g10/import.c | 9 | ||||
-rw-r--r-- | g10/key-clean.c | 41 | ||||
-rw-r--r-- | g10/key-clean.h | 5 | ||||
-rw-r--r-- | g10/keydb.h | 2 | ||||
-rw-r--r-- | g10/keyedit.c | 16 | ||||
-rw-r--r-- | g10/keyid.c | 178 | ||||
-rw-r--r-- | g10/main.h | 2 | ||||
-rw-r--r-- | g10/mainproc.c | 21 | ||||
-rw-r--r-- | g10/options.h | 15 | ||||
-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/tdbdump.c | 6 | ||||
-rw-r--r-- | g10/tdbio.c | 16 | ||||
-rw-r--r-- | g10/tdbio.h | 3 | ||||
-rw-r--r-- | g10/test-stubs.c | 18 | ||||
-rw-r--r-- | g10/test.c | 1 | ||||
-rw-r--r-- | g10/trustdb.c | 110 | ||||
-rw-r--r-- | g10/verify.c | 33 |
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, @@ -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); + } +} |