From 1be7882344c5b3eae35539f6c3f490df197574bf Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 4 Sep 2023 16:34:55 +0200 Subject: [PATCH] gpg: Add option --with-v5-fingerprint * g10/gpg.c (oWithV5Fingerprint): New. (opts): Add new option. (main): Set option. * g10/options.h (opt): Add with_v5_fingerprint. * g10/keyid.c (hash_public_key): Factor out to ... (do_hash_public_key): this. Add new arg to foce v5 style hashing. (v5_fingerprint_from_pk): New. (v5hexfingerprint): New. * g10/keylist.c (print_fingerprint): Print v5 fingerprint for v4 keys if the option is set. -- GnuPG-bug-id: 6705 --- doc/gpg.texi | 5 +++ g10/gpg.c | 13 ++++++++ g10/keydb.h | 2 ++ g10/keyid.c | 84 +++++++++++++++++++++++++++++++++++++++++++++------ g10/keylist.c | 6 ++++ g10/options.h | 1 + 6 files changed, 102 insertions(+), 9 deletions(-) diff --git a/doc/gpg.texi b/doc/gpg.texi index 15b3243d0..ce72afbf5 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -2849,6 +2849,11 @@ achieved by using the @option{--with-fingerprint} twice but by using this option along with keyid-format "none" a compact fingerprint is printed. +@item --with-v5-fingerprint +@opindex with-v5-fingerprint +In a colon mode listing emit "fp2" lines for version 4 OpenPGP keys +having a v5 style fingerprint of the key. + @item --with-icao-spelling @opindex with-icao-spelling Print the ICAO spelling of the fingerprint in addition to the hex digits. diff --git a/g10/gpg.c b/g10/gpg.c index 54e74f5b1..ec6af0eb9 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -203,6 +203,7 @@ enum cmd_and_opt_values oAskCertLevel, oNoAskCertLevel, oFingerprint, + oWithV5Fingerprint, oWithFingerprint, oWithSubkeyFingerprint, oWithICAOSpelling, @@ -816,6 +817,7 @@ static gpgrt_opt_t opts[] = { ARGPARSE_s_n (oWithKeyData,"with-key-data", "@"), ARGPARSE_s_n (oWithSigList,"with-sig-list", "@"), ARGPARSE_s_n (oWithSigCheck,"with-sig-check", "@"), + ARGPARSE_s_n (oWithV5Fingerprint, "with-v5-fingerprint", "@"), ARGPARSE_s_n (oWithFingerprint, "with-fingerprint", "@"), ARGPARSE_s_n (oWithSubkeyFingerprint, "with-subkey-fingerprint", "@"), ARGPARSE_s_n (oWithSubkeyFingerprint, "with-subkey-fingerprints", "@"), @@ -2887,6 +2889,9 @@ main (int argc, char **argv) opt_log_time = 1; break; + case oWithV5Fingerprint: + opt.with_v5_fingerprint = 1; + break; case oWithFingerprint: opt.with_fingerprint = 1; opt.fingerprint++; @@ -3791,6 +3796,14 @@ main (int argc, char **argv) g10_exit(2); } + /* Set depended fingerprint options. */ + if (opt.with_v5_fingerprint && !opt.with_fingerprint) + { + opt.with_fingerprint = 1; + if (!opt.fingerprint) + opt.fingerprint = 1; + } + /* Process common component options. */ if (parse_comopt (GNUPG_MODULE_NAME_GPG, debug_argparser)) { diff --git a/g10/keydb.h b/g10/keydb.h index 1a66d664e..b18f6e93a 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -570,8 +570,10 @@ const char *colon_datestr_from_pk (PKT_public_key *pk); const char *colon_datestr_from_sig (PKT_signature *sig); 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]); 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, char *buffer, size_t buflen); gpg_error_t keygrip_from_pk (PKT_public_key *pk, unsigned char *array); diff --git a/g10/keyid.c b/g10/keyid.c index 7cf9803e2..1dbcd3e0e 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -2,7 +2,7 @@ * Copyright (C) 1998, 1999, 2000, 2001, 2003, * 2004, 2006, 2010 Free Software Foundation, Inc. * Copyright (C) 2014 Werner Koch - * Copyright (C) 2016 g10 Code GmbH + * Copyright (C) 2016, 2023 g10 Code GmbH * * This file is part of GnuPG. * @@ -18,6 +18,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see . + * SPDX-License-Identifier: GPL-3.0-or-later */ #include @@ -144,10 +145,11 @@ pubkey_string (PKT_public_key *pk, char *buffer, size_t bufsize) } -/* Hash a public key. This function is useful for v4 and v5 - * fingerprints and for v3 or v4 key signing. */ -void -hash_public_key (gcry_md_hd_t md, PKT_public_key *pk) +/* 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. */ +static void +do_hash_public_key (gcry_md_hd_t md, PKT_public_key *pk, int use_v5) { unsigned int n; unsigned int nn[PUBKEY_MAX_NPKEY]; @@ -156,9 +158,8 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk) unsigned int nbits; size_t nbytes; int npkey = pubkey_get_npkey (pk->pubkey_algo); - int is_v5 = pk->version == 5; - n = is_v5? 10 : 6; + n = use_v5? 10 : 6; /* FIXME: We can avoid the extra malloc by calling only the first mpi_print here which computes the required length and calling the real mpi_print only at the end. The speed advantage would only be @@ -235,13 +236,14 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk) } } - if (is_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 >> 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 @@ -258,7 +260,7 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk) gcry_md_putc ( md, pk->pubkey_algo ); - if (is_v5) + if (use_v5) { n -= 10; gcry_md_putc ( md, n >> 24 ); @@ -285,6 +287,15 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk) } +/* Hash a public key. This function is useful for v4 and v5 + * fingerprints and for v3 or v4 key signing. */ +void +hash_public_key (gcry_md_hd_t md, PKT_public_key *pk) +{ + do_hash_public_key (md, pk, pk->version); +} + + /* fixme: Check whether we can replace this function or if not describe why we need it. */ u32 @@ -893,6 +904,37 @@ fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len) } +/* + * Return a byte array with the fingerprint for the given PK/SK The + * length of the array is returned in ret_len. Caller must free the + * array or provide an array of length MAX_FINGERPRINT_LEN. This + * version creates a v5 fingerprint even vor v4 keys. + */ +byte * +v5_fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len) +{ + const byte *dp; + gcry_md_hd_t md; + + if (pk->version == 5) + return fingerprint_from_pk (pk, array, ret_len); + + if (gcry_md_open (&md, GCRY_MD_SHA256, 0)) + BUG (); + do_hash_public_key (md, pk, 1); + gcry_md_final (md); + dp = gcry_md_read (md, 0); + if (!array) + array = xmalloc (32); + memcpy (array, dp, 32); + gcry_md_close (md); + + if (ret_len) + *ret_len = 32; + return array; +} + + /* * Get FPR20 for the given PK/SK into ARRAY. * @@ -952,6 +994,30 @@ hexfingerprint (PKT_public_key *pk, char *buffer, size_t buflen) } +/* Same as hexfingerprint but returns a v5 fingerprint also for a v4 + * key. */ +char * +v5hexfingerprint (PKT_public_key *pk, char *buffer, size_t buflen) +{ + char fprbuf[32]; + + if (pk->version == 5) + return hexfingerprint (pk, buffer, buflen); + + if (!buffer) + { + buffer = xtrymalloc (2 * 32 + 1); + if (!buffer) + return NULL; + } + else if (buflen < 2 * 32 + 1) + log_fatal ("%s: buffer too short (%zu)\n", __func__, buflen); + + v5_fingerprint_from_pk (pk, fprbuf, NULL); + return bin2hex (fprbuf, 32, buffer); +} + + /* Pretty print a hex fingerprint. If BUFFER is NULL the result is a malloc'd string. If BUFFER is not NULL the result will be copied into this buffer. In the latter case BUFLEN describes the length diff --git a/g10/keylist.c b/g10/keylist.c index 8b7c597cb..d0ebfc86f 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -2413,6 +2413,12 @@ print_fingerprint (ctrl_t ctrl, estream_t override_fp, if (with_colons && !mode) { es_fprintf (fp, "fpr:::::::::%s:", hexfpr); + if (opt.with_v5_fingerprint && pk->version == 4) + { + char *v5fpr = v5hexfingerprint (pk, NULL, 0); + es_fprintf (fp, "\nfp2:::::::::%s:", v5fpr); + xfree (v5fpr); + } } else if (compact && !opt.fingerprint && !opt.with_fingerprint) { diff --git a/g10/options.h b/g10/options.h index 327a6a06f..5326ac8d8 100644 --- a/g10/options.h +++ b/g10/options.h @@ -79,6 +79,7 @@ struct int with_colons; int with_key_data; int with_icao_spelling; /* Print ICAO spelling with fingerprints. */ + int with_v5_fingerprint; /* Option --with-v5-fingerprint active. */ int with_fingerprint; /* Option --with-fingerprint active. */ int with_subkey_fingerprint; /* Option --with-subkey-fingerprint active. */ int with_keygrip; /* Option --with-keygrip active. */