gpg: Implemented latest rfc4880bis version 5 packet hashing.

* configure.ac (AC_CHECK_SIZEOF): Test size_t.
* g10/sig-check.c (check_signature_end_simple): Support v5 signatures
as per current rfc4880bis.  For correctness also allow for N > 2^32.
* g10/sign.c (pt_extra_hash_data_t): New.
(hash_sigversion_to_magic): New arg EXTRAHASH.
(write_plaintext_packet): New arg R_EXTRAHASH.
(write_signature_packets): Pass EXTRAHASH.
(sign_file): Ditto.
(sign_symencrypt_file): Ditto.
--

Take care: The code path for v5 sigs has not yet been tested.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2019-03-12 11:09:52 +01:00
parent f199b627ce
commit a21ca3a1ef
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
3 changed files with 131 additions and 33 deletions

View File

@ -1367,6 +1367,7 @@ AC_CHECK_SIZEOF(unsigned short)
AC_CHECK_SIZEOF(unsigned int) AC_CHECK_SIZEOF(unsigned int)
AC_CHECK_SIZEOF(unsigned long) AC_CHECK_SIZEOF(unsigned long)
AC_CHECK_SIZEOF(unsigned long long) AC_CHECK_SIZEOF(unsigned long long)
AC_CHECK_SIZEOF(size_t)
AC_HEADER_TIME AC_HEADER_TIME
AC_CHECK_SIZEOF(time_t,,[[ AC_CHECK_SIZEOF(time_t,,[[
#include <stdio.h> #include <stdio.h>

View File

@ -513,6 +513,7 @@ check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig,
byte buf[10]; byte buf[10];
int i; int i;
size_t n; size_t n;
gcry_md_putc (digest, sig->pubkey_algo); gcry_md_putc (digest, sig->pubkey_algo);
gcry_md_putc (digest, sig->digest_algo); gcry_md_putc (digest, sig->digest_algo);
if (sig->hashed) if (sig->hashed)
@ -531,22 +532,39 @@ check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig,
gcry_md_putc (digest, 0); gcry_md_putc (digest, 0);
n = 6; n = 6;
} }
/* add some magic per Section 5.2.4 of RFC 4880. */ /* Hash data from the literal data packet. */
i = 0; if (sig->version >= 5
buf[i++] = sig->version; && (sig->sig_class == 0x00 || sig->sig_class == 0x01))
buf[i++] = 0xff; {
if (sig->version >= 5) /* - One octet content format
{ * - File name (one octet length followed by the name)
buf[i++] = 0; * - Four octet timestamp */
buf[i++] = 0; memset (buf, 0, 6);
buf[i++] = 0; gcry_md_write (digest, buf, 6);
buf[i++] = 0; }
} /* Add some magic per Section 5.2.4 of RFC 4880. */
buf[i++] = n >> 24; i = 0;
buf[i++] = n >> 16; buf[i++] = sig->version;
buf[i++] = n >> 8; buf[i++] = 0xff;
buf[i++] = n; if (sig->version >= 5)
gcry_md_write (digest, buf, i); {
#if SIZEOF_SIZE_T > 4
buf[i++] = n >> 56;
buf[i++] = n >> 48;
buf[i++] = n >> 40;
buf[i++] = n >> 32;
#else
buf[i++] = 0;
buf[i++] = 0;
buf[i++] = 0;
buf[i++] = 0;
#endif
}
buf[i++] = n >> 24;
buf[i++] = n >> 16;
buf[i++] = n >> 8;
buf[i++] = n;
gcry_md_write (digest, buf, i);
} }
gcry_md_final( digest ); gcry_md_final( digest );

View File

@ -49,7 +49,19 @@
#define LF "\n" #define LF "\n"
#endif #endif
static int recipient_digest_algo=0; /* A type for the extra data we hash into v5 signature packets. */
struct pt_extra_hash_data_s
{
unsigned char mode;
u32 timestamp;
unsigned char namelen;
char name[1];
};
typedef struct pt_extra_hash_data_s *pt_extra_hash_data_t;
/* Hack */
static int recipient_digest_algo;
/* /*
@ -216,10 +228,13 @@ hash_uid (gcry_md_hd_t md, int sigversion, const PKT_user_id *uid)
/* /*
* Helper to hash some parts from the signature * Helper to hash some parts from the signature. EXTRAHASH gives the
* extra data to be hashed into v5 signatures; it may by NULL for
* detached signatures.
*/ */
static void static void
hash_sigversion_to_magic (gcry_md_hd_t md, const PKT_signature *sig) hash_sigversion_to_magic (gcry_md_hd_t md, const PKT_signature *sig,
pt_extra_hash_data_t extrahash)
{ {
byte buf[10]; byte buf[10];
int i; int i;
@ -243,12 +258,39 @@ hash_sigversion_to_magic (gcry_md_hd_t md, const PKT_signature *sig)
gcry_md_putc (md, 0); gcry_md_putc (md, 0);
n = 6; n = 6;
} }
/* Hash data from the literal data packet. */
if (sig->version >= 5 && (sig->sig_class == 0x00 || sig->sig_class == 0x01))
{
/* - One octet content format
* - File name (one octet length followed by the name)
* - Four octet timestamp */
if (extrahash)
{
buf[0] = extrahash->mode;
buf[1] = extrahash->namelen;
gcry_md_write (md, buf, 2);
if (extrahash->namelen)
gcry_md_write (md, extrahash->name, extrahash->namelen);
buf[0] = extrahash->timestamp >> 24;
buf[1] = extrahash->timestamp >> 16;
buf[2] = extrahash->timestamp >> 8;
buf[3] = extrahash->timestamp;
gcry_md_write (md, buf, 4);
}
else /* Detached signatures */
{
memset (buf, 0, 6);
gcry_md_write (md, buf, 6);
}
}
/* Add some magic. */ /* Add some magic. */
i = 0; i = 0;
buf[i++] = sig->version; buf[i++] = sig->version;
buf[i++] = 0xff; buf[i++] = 0xff;
if (sig->version >= 5) if (sig->version >= 5)
{ {
/* Note: We don't hashed any data larger than 2^32 and thus we
* can always use 0 here. See also note below. */
buf[i++] = 0; buf[i++] = 0;
buf[i++] = 0; buf[i++] = 0;
buf[i++] = 0; buf[i++] = 0;
@ -633,10 +675,14 @@ write_onepass_sig_packets (SK_LIST sk_list, IOBUF out, int sigclass )
/* /*
* Helper to write the plaintext (literal data) packet * Helper to write the plaintext (literal data) packet. At
* R_EXTRAHASH a malloced object with the with the extra data hashed
* into v5 signatures is stored.
*/ */
static int static int
write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode) write_plaintext_packet (iobuf_t out, iobuf_t inp,
const char *fname, int ptmode,
pt_extra_hash_data_t *r_extrahash)
{ {
PKT_plaintext *pt = NULL; PKT_plaintext *pt = NULL;
u32 filesize; u32 filesize;
@ -691,6 +737,19 @@ write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode)
if ((rc = build_packet (out, &pkt))) if ((rc = build_packet (out, &pkt)))
log_error ("build_packet(PLAINTEXT) failed: %s\n", log_error ("build_packet(PLAINTEXT) failed: %s\n",
gpg_strerror (rc) ); gpg_strerror (rc) );
*r_extrahash = xtrymalloc (sizeof **r_extrahash + pt->namelen);
if (!*r_extrahash)
rc = gpg_error_from_syserror ();
else
{
(*r_extrahash)->mode = pt->mode;
(*r_extrahash)->timestamp = pt->timestamp;
(*r_extrahash)->namelen = pt->namelen;
/* Note that the last byte or NAME won't be initialized
* becuase we don't need it. */
memcpy ((*r_extrahash)->name, pt->name, pt->namelen);
}
pt->buf = NULL; pt->buf = NULL;
free_packet (&pkt, NULL); free_packet (&pkt, NULL);
} }
@ -699,6 +758,18 @@ write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode)
byte copy_buffer[4096]; byte copy_buffer[4096];
int bytes_copied; int bytes_copied;
*r_extrahash = xtrymalloc (sizeof **r_extrahash);
if (!*r_extrahash)
{
rc = gpg_error_from_syserror ();
goto leave;
}
/* FIXME: We need to parse INP to get the to be hashed data from
* it. */
(*r_extrahash)->mode = 0;
(*r_extrahash)->timestamp = 0;
(*r_extrahash)->namelen = 0;
while ((bytes_copied = iobuf_read (inp, copy_buffer, 4096)) != -1) while ((bytes_copied = iobuf_read (inp, copy_buffer, 4096)) != -1)
if ((rc = iobuf_write (out, copy_buffer, bytes_copied))) if ((rc = iobuf_write (out, copy_buffer, bytes_copied)))
{ {
@ -708,19 +779,21 @@ write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode)
} }
wipememory (copy_buffer, 4096); /* burn buffer */ wipememory (copy_buffer, 4096); /* burn buffer */
} }
/* fixme: it seems that we never freed pt/pkt */
leave:
return rc; return rc;
} }
/* /*
* Write the signatures from the SK_LIST to OUT. HASH must be a non-finalized * Write the signatures from the SK_LIST to OUT. HASH must be a
* hash which will not be changes here. * non-finalized hash which will not be changes here. EXTRAHASH is
* either NULL or the extra data tro be hashed into v5 signatures.
*/ */
static int static int
write_signature_packets (ctrl_t ctrl, write_signature_packets (ctrl_t ctrl,
SK_LIST sk_list, IOBUF out, gcry_md_hd_t hash, SK_LIST sk_list, IOBUF out, gcry_md_hd_t hash,
pt_extra_hash_data_t extrahash,
int sigclass, u32 timestamp, u32 duration, int sigclass, u32 timestamp, u32 duration,
int status_letter, const char *cache_nonce) int status_letter, const char *cache_nonce)
{ {
@ -744,7 +817,7 @@ write_signature_packets (ctrl_t ctrl,
if (pk->version >= 5) if (pk->version >= 5)
sig->version = 5; /* Required for v5 keys. */ sig->version = 5; /* Required for v5 keys. */
else else
sig->version = 4; /*Required. */ sig->version = 4; /* Required. */
keyid_from_pk (pk, sig->keyid); keyid_from_pk (pk, sig->keyid);
sig->digest_algo = hash_for (pk); sig->digest_algo = hash_for (pk);
@ -762,7 +835,7 @@ write_signature_packets (ctrl_t ctrl,
build_sig_subpkt_from_sig (sig, pk); build_sig_subpkt_from_sig (sig, pk);
mk_notation_policy_etc (sig, NULL, pk); mk_notation_policy_etc (sig, NULL, pk);
hash_sigversion_to_magic (md, sig); hash_sigversion_to_magic (md, sig, extrahash);
gcry_md_final (md); gcry_md_final (md);
rc = do_sign (ctrl, pk, sig, md, hash_for (pk), cache_nonce); rc = do_sign (ctrl, pk, sig, md, hash_for (pk), cache_nonce);
@ -826,6 +899,7 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
SK_LIST sk_rover = NULL; SK_LIST sk_rover = NULL;
int multifile = 0; int multifile = 0;
u32 duration=0; u32 duration=0;
pt_extra_hash_data_t extrahash = NULL;
pfx = new_progress_context (); pfx = new_progress_context ();
afx = new_armor_context (); afx = new_armor_context ();
@ -1125,7 +1199,8 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
{ {
rc = write_plaintext_packet (out, inp, fname, rc = write_plaintext_packet (out, inp, fname,
(opt.textmode && !outfile) ? (opt.textmode && !outfile) ?
(opt.mimemode? 'm' : 't') : 'b'); (opt.mimemode? 'm' : 't') : 'b',
&extrahash);
} }
/* Catch errors from above. */ /* Catch errors from above. */
@ -1133,7 +1208,7 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
goto leave; goto leave;
/* Write the signatures. */ /* Write the signatures. */
rc = write_signature_packets (ctrl, sk_list, out, mfx.md, rc = write_signature_packets (ctrl, sk_list, out, mfx.md, extrahash,
opt.textmode && !outfile? 0x01 : 0x00, opt.textmode && !outfile? 0x01 : 0x00,
0, duration, detached ? 'D':'S', NULL); 0, duration, detached ? 'D':'S', NULL);
if (rc) if (rc)
@ -1156,6 +1231,7 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
recipient_digest_algo = 0; recipient_digest_algo = 0;
release_progress_context (pfx); release_progress_context (pfx);
release_armor_context (afx); release_armor_context (afx);
xfree (extrahash);
return rc; return rc;
} }
@ -1286,7 +1362,7 @@ clearsign_file (ctrl_t ctrl,
push_armor_filter (afx, out); push_armor_filter (afx, out);
/* Write the signatures. */ /* Write the signatures. */
rc = write_signature_packets (ctrl, sk_list, out, textmd, 0x01, 0, rc = write_signature_packets (ctrl, sk_list, out, textmd, NULL, 0x01, 0,
duration, 'C', NULL); duration, 'C', NULL);
if (rc) if (rc)
goto leave; goto leave;
@ -1328,6 +1404,7 @@ sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr)
int algo; int algo;
u32 duration = 0; u32 duration = 0;
int canceled; int canceled;
pt_extra_hash_data_t extrahash = NULL;
pfx = new_progress_context (); pfx = new_progress_context ();
afx = new_armor_context (); afx = new_armor_context ();
@ -1452,13 +1529,14 @@ sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr)
/* Pipe data through all filters; i.e. write the signed stuff. */ /* Pipe data through all filters; i.e. write the signed stuff. */
/* (current filters: zip - encrypt - armor) */ /* (current filters: zip - encrypt - armor) */
rc = write_plaintext_packet (out, inp, fname, rc = write_plaintext_packet (out, inp, fname,
opt.textmode ? (opt.mimemode?'m':'t'):'b'); opt.textmode ? (opt.mimemode?'m':'t'):'b',
&extrahash);
if (rc) if (rc)
goto leave; goto leave;
/* Write the signatures. */ /* Write the signatures. */
/* (current filters: zip - encrypt - armor) */ /* (current filters: zip - encrypt - armor) */
rc = write_signature_packets (ctrl, sk_list, out, mfx.md, rc = write_signature_packets (ctrl, sk_list, out, mfx.md, extrahash,
opt.textmode? 0x01 : 0x00, opt.textmode? 0x01 : 0x00,
0, duration, 'S', NULL); 0, duration, 'S', NULL);
if (rc) if (rc)
@ -1480,6 +1558,7 @@ sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr)
xfree (s2k); xfree (s2k);
release_progress_context (pfx); release_progress_context (pfx);
release_armor_context (afx); release_armor_context (afx);
xfree (extrahash);
return rc; return rc;
} }
@ -1599,7 +1678,7 @@ make_keysig_packet (ctrl_t ctrl,
if (!rc) if (!rc)
{ {
hash_sigversion_to_magic (md, sig); hash_sigversion_to_magic (md, sig, NULL);
gcry_md_final (md); gcry_md_final (md);
rc = complete_sig (ctrl, sig, pksk, md, cache_nonce); rc = complete_sig (ctrl, sig, pksk, md, cache_nonce);
} }
@ -1699,7 +1778,7 @@ update_keysig_packet (ctrl_t ctrl,
if (!rc) if (!rc)
{ {
hash_sigversion_to_magic (md, sig); hash_sigversion_to_magic (md, sig, NULL);
gcry_md_final (md); gcry_md_final (md);
rc = complete_sig (ctrl, sig, pksk, md, NULL); rc = complete_sig (ctrl, sig, pksk, md, NULL);
} }