gpg: Implement v5 keys and v5 signatures.

* g10/build-packet.c (gpg_mpi_write): New optional arg
R_NWRITTEN.  Allow NULL for OUT.  Change all callers.
(do_key): Support v5 keys.
(build_sig_subpkt_from_sig): Support 32 byte fingerprints.
* g10/parse-packet.c (parse_signature): First try to set the keyid
from the issuer fingerprint.
(parse_key): Support v5 keys.
(create_gpg_control): Better make sure to always allocate the static
size of the struct in case future compilers print warnings.
* g10/keyid.c (hash_public_key): Add v5 support.
(keyid_from_pk): Ditto.
(keyid_from_fingerprint): Ditto.
(fingerprint_from_pk): Ditto.
* g10/keygen.c (KEYGEN_FLAG_CREATE_V5_KEY): New.
(pVERSION, pSUBVERSION): New.
(add_feature_v5): New.
(keygen_upd_std_prefs): Call it.
(do_create_from_keygrip): Add arg keygen_flags and support the v5
flag.
(common_gen): Support the v5 flag.
(parse_key_parameter_part): New flags v4 and v5.
(parse_key_parameter_string): Add args for version and subversion.
(read_parameter_file): New keywords "Key-Version" and
"Subkey-Version".
(quickgen_set_para): Add arg 'version'.
(quick_generate_keypair, generate_keypair): Support version parms.
(do_generate_keypair): Support v5 key flag.
(generate_subkeypair): Ditto.
(generate_card_subkeypair): Preparse for keyflags.
(gen_card_key): Ditto.
* g10/sig-check.c (check_signature2): Add args extrahash and
extrahashlen.
(check_signature_end): Ditto.
(check_signature_end_simple): Ditto.  Use them.
* g10/mainproc.c (proc_plaintext): Put extra hash infor into the
control packet.
(do_check_sig): Add args extrahas and extrahashlen and pass them on.
(issuer_fpr_raw): Support 32 byte fingerprint.
(check_sig_and_print): get extra hash data and pass it on.
--

Note that this is only basic support and requires more fine
tuning/fixing.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2019-03-14 11:20:07 +01:00
parent f40e9d6a52
commit 01c87d4ce2
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
8 changed files with 565 additions and 197 deletions

View File

@ -243,12 +243,15 @@ build_packet_and_meta (iobuf_t out, PACKET *pkt)
/*
* Write the mpi A to OUT.
* Write the mpi A to OUT. If R_NWRITTEN is not NULL the number of
* bytes written is stored there. To only get the number of bytes
* which would be written NULL may be passed for OUT.
*/
gpg_error_t
gpg_mpi_write (iobuf_t out, gcry_mpi_t a)
gpg_mpi_write (iobuf_t out, gcry_mpi_t a, unsigned int *r_nwritten)
{
int rc;
gpg_error_t err;
unsigned int nwritten = 0;
if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
{
@ -277,9 +280,17 @@ gpg_mpi_write (iobuf_t out, gcry_mpi_t a)
/* gcry_log_debughex (" ", p, (nbits+7)/8); */
lenhdr[0] = nbits >> 8;
lenhdr[1] = nbits;
rc = iobuf_write (out, lenhdr, 2);
if (!rc && p)
rc = iobuf_write (out, p, (nbits+7)/8);
err = out? iobuf_write (out, lenhdr, 2) : 0;
if (!err)
{
nwritten += 2;
if (p)
{
err = out? iobuf_write (out, p, (nbits+7)/8) : 0;
if (!err)
nwritten += (nbits+7)/8;
}
}
}
else
{
@ -287,18 +298,25 @@ gpg_mpi_write (iobuf_t out, gcry_mpi_t a)
size_t nbytes;
nbytes = DIM(buffer);
rc = gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes, &nbytes, a );
if( !rc )
rc = iobuf_write( out, buffer, nbytes );
else if (gpg_err_code(rc) == GPG_ERR_TOO_SHORT )
err = gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes, &nbytes, a );
if (!err)
{
err = out? iobuf_write (out, buffer, nbytes) : 0;
if (!err)
nwritten += nbytes;
}
else if (gpg_err_code (err) == GPG_ERR_TOO_SHORT )
{
log_info ("mpi too large (%u bits)\n", gcry_mpi_get_nbits (a));
/* The buffer was too small. We better tell the user about the MPI. */
rc = gpg_error (GPG_ERR_TOO_LARGE);
/* The buffer was too small. We better tell the user about
* the MPI. */
err = gpg_error (GPG_ERR_TOO_LARGE);
}
}
return rc;
if (r_nwritten)
*r_nwritten = nwritten;
return err;
}
@ -463,29 +481,29 @@ static int
do_key (iobuf_t out, int ctb, PKT_public_key *pk)
{
gpg_error_t err = 0;
/* The length of the body is stored in the packet's header, which
occurs before the body. Unfortunately, we don't know the length
of the packet's body until we've written all of the data! To
work around this, we first write the data into this temporary
buffer, then generate the header, and finally copy the contents
of this buffer to OUT. */
iobuf_t a = iobuf_temp();
iobuf_t a;
int i, nskey, npkey;
u32 pkbytes = 0;
int is_v5;
log_assert (pk->version == 0 || pk->version == 4);
log_assert (pk->version == 0 || pk->version == 4 || pk->version == 5);
log_assert (ctb_pkttype (ctb) == PKT_PUBLIC_KEY
|| ctb_pkttype (ctb) == PKT_PUBLIC_SUBKEY
|| ctb_pkttype (ctb) == PKT_SECRET_KEY
|| ctb_pkttype (ctb) == PKT_SECRET_SUBKEY);
/* Write the version number - if none is specified, use 4 */
if ( !pk->version )
iobuf_put ( a, 4 );
else
iobuf_put ( a, pk->version );
write_32 (a, pk->timestamp );
/* The length of the body is stored in the packet's header, which
* occurs before the body. Unfortunately, we don't know the length
* of the packet's body until we've written all of the data! To
* work around this, we first write the data into this temporary
* buffer, then generate the header, and finally copy the content
* of this buffer to OUT. */
a = iobuf_temp();
iobuf_put (a, pk->pubkey_algo );
/* Note that the Version number, Timestamp, Algo, and the v5 Key
* material count are written at the end of the function. */
is_v5 = (pk->version == 5);
/* Get number of secret and public parameters. They are held in one
array: the public ones followed by the secret ones. */
@ -509,11 +527,13 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
|| (pk->pubkey_algo == PUBKEY_ALGO_ECDH && (i == 0 || i == 2)))
err = gpg_mpi_write_nohdr (a, pk->pkey[i]);
else
err = gpg_mpi_write (a, pk->pkey[i]);
err = gpg_mpi_write (a, pk->pkey[i], NULL);
if (err)
goto leave;
}
/* Record the length of the public key part. */
pkbytes = iobuf_get_temp_length (a);
if (pk->seckey_info)
{
@ -523,9 +543,26 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
/* Build the header for protected (encrypted) secret parameters. */
if (ski->is_protected)
{
/* OpenPGP protection according to rfc2440. */
iobuf_put (a, ski->sha1chk? 0xfe : 0xff);
iobuf_put (a, ski->algo);
iobuf_put (a, ski->sha1chk? 0xfe : 0xff); /* S2k usage. */
if (is_v5)
{
/* For a v5 key determine the count of the following
* key-protection material and write it. */
int count = 1; /* Pubkey algo octet. */
if (ski->s2k.mode >= 1000)
count += 6; /* GNU specific mode descriptor. */
else
count += 2; /* Mode and hash algo. */
if (ski->s2k.mode == 1 || ski->s2k.mode == 3)
count += 8; /* Salt. */
if (ski->s2k.mode == 3)
count++; /* S2K.COUNT */
if (ski->s2k.mode != 1001 && ski->s2k.mode != 1002)
count += ski->ivlen;
iobuf_put (a, count);
}
iobuf_put (a, ski->algo); /* Pubkey algo octet. */
if (ski->s2k.mode >= 1000)
{
/* These modes are not possible in OpenPGP, we use them
@ -556,13 +593,24 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
}
else /* Not protected. */
iobuf_put (a, 0 );
{
iobuf_put (a, 0 ); /* S2K usage = not protected. */
if (is_v5)
iobuf_put (a, 0); /* Zero octets of key-protection
* material follows. */
}
if (ski->s2k.mode == 1001)
; /* GnuPG extension - don't write a secret key at all. */
{
/* GnuPG extension - don't write a secret key at all. */
if (is_v5)
write_32 (a, 0); /* Zero octets of key material. */
}
else if (ski->s2k.mode == 1002)
{
/* GnuPG extension - divert to OpenPGP smartcard. */
if (is_v5)
write_32 (a, 1 + ski->ivlen);
/* Length of the serial number or 0 for no serial number. */
iobuf_put (a, ski->ivlen );
/* The serial number gets stored in the IV field. */
@ -576,15 +624,36 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
log_assert (gcry_mpi_get_flag (pk->pkey[npkey], GCRYMPI_FLAG_OPAQUE));
p = gcry_mpi_get_opaque (pk->pkey[npkey], &ndatabits);
/* For v5 keys we first write the number of octets of the
* following encrypted key material. */
if (is_v5)
write_32 (a, p? (ndatabits+7)/8 : 0);
if (p)
iobuf_write (a, p, (ndatabits+7)/8 );
}
else
{
/* Non-protected key. */
if (is_v5)
{
unsigned int skbytes = 0;
unsigned int n;
int j;
for (j=i; j < nskey; j++ )
{
if ((err = gpg_mpi_write (NULL, pk->pkey[j], &n)))
goto leave;
skbytes += n;
}
write_32 (a, skbytes);
}
for ( ; i < nskey; i++ )
if ( (err = gpg_mpi_write (a, pk->pkey[i])))
if ( (err = gpg_mpi_write (a, pk->pkey[i], NULL)))
goto leave;
write_16 (a, ski->csum );
}
}
@ -593,11 +662,23 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
if (!err)
{
/* Build the header of the packet - which we must do after
writing all the other stuff, so that we know the length of
the packet */
write_header2 (out, ctb, iobuf_get_temp_length(a), 0);
* writing all the other stuff, so that we know the length of
* the packet */
u32 len = iobuf_get_temp_length (a);
len += 1; /* version number */
len += 4; /* timestamp */
len += 1; /* algo */
if (is_v5)
len += 4; /* public key material count */
write_header2 (out, ctb, len, 0);
/* And finally write it out to the real stream. */
err = iobuf_write_temp (out, a);
iobuf_put (out, pk->version? pk->version : 4); /* version number */
write_32 (out, pk->timestamp );
iobuf_put (out, pk->pubkey_algo); /* algo */
if (is_v5)
write_32 (out, pkbytes); /* public key material count */
err = iobuf_write_temp (out, a); /* pub and sec key material */
}
iobuf_close (a); /* Close the temporary buffer */
@ -688,7 +769,7 @@ do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
if (enc->pubkey_algo == PUBKEY_ALGO_ECDH && i == 1)
rc = gpg_mpi_write_nohdr (a, enc->data[i]);
else
rc = gpg_mpi_write (a, enc->data[i]);
rc = gpg_mpi_write (a, enc->data[i], NULL);
}
if (!rc)
@ -1135,10 +1216,10 @@ build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk)
/* Write the new ISSUER_FPR subpacket. */
fingerprint_from_pk (pksk, buf+1, &fprlen);
if (fprlen == 20)
if (fprlen == 20 || fprlen == 32)
{
buf[0] = pksk->version;
build_sig_subpkt (sig, SIGSUBPKT_ISSUER_FPR, buf, 21);
build_sig_subpkt (sig, SIGSUBPKT_ISSUER_FPR, buf, fprlen + 1);
}
/* Write the timestamp. */
@ -1567,7 +1648,7 @@ do_signature( IOBUF out, int ctb, PKT_signature *sig )
if ( !n )
write_fake_data( a, sig->data[0] );
for (i=0; i < n && !rc ; i++ )
rc = gpg_mpi_write (a, sig->data[i] );
rc = gpg_mpi_write (a, sig->data[i], NULL);
if (!rc)
{

View File

@ -1,6 +1,6 @@
/* keygen.c - Generate a key pair
* Copyright (C) 1998-2007, 2009-2011 Free Software Foundation, Inc.
* Copyright (C) 2014, 2015, 2016 Werner Koch
* Copyright (C) 2014, 2015, 2016, 2017, 2018 Werner Koch
*
* This file is part of GnuPG.
*
@ -59,6 +59,7 @@ const char *default_expiration_interval = "2y";
/* Flag bits used during key generation. */
#define KEYGEN_FLAG_NO_PROTECTION 1
#define KEYGEN_FLAG_TRANSIENT_KEY 2
#define KEYGEN_FLAG_CREATE_V5_KEY 4
/* Maximum number of supported algorithm preferences. */
#define MAX_PREFS 30
@ -90,7 +91,9 @@ enum para_name {
pHANDLE,
pKEYSERVER,
pKEYGRIP,
pSUBKEYGRIP
pSUBKEYGRIP,
pVERSION, /* Desired version of the key packet. */
pSUBVERSION, /* Ditto for the subpacket. */
};
struct para_data_s {
@ -148,13 +151,13 @@ static gpg_error_t parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
const char *expirestr,
int *r_algo, unsigned int *r_usage,
u32 *r_expire, unsigned int *r_nbits,
const char **r_curve);
const char **r_curve, int *r_version);
static void do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
struct output_control_s *outctrl, int card );
static int write_keyblock (iobuf_t out, kbnode_t node);
static gpg_error_t gen_card_key (int keyno, int algo, int is_primary,
kbnode_t pub_root, u32 *timestamp,
u32 expireval);
u32 expireval, int keygen_flags);
static unsigned int get_keysize_range (int algo,
unsigned int *min, unsigned int *max);
@ -760,6 +763,48 @@ add_feature_aead (PKT_signature *sig, int enabled)
}
static void
add_feature_v5 (PKT_signature *sig, int enabled)
{
const byte *s;
size_t n;
int i;
char *buf;
s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n );
if (s && n && ((enabled && (s[0] & 0x04)) || (!enabled && !(s[0] & 0x04))))
return; /* Already set or cleared */
if (!s || !n)
{ /* Create a new one */
n = 1;
buf = xmalloc_clear (n);
}
else
{
buf = xmalloc (n);
memcpy (buf, s, n);
}
if (enabled)
buf[0] |= 0x04; /* v5 key supported */
else
buf[0] &= ~0x04;
/* Are there any bits set? */
for (i=0; i < n; i++)
if (buf[i])
break;
if (i == n)
delete_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES);
else
build_sig_subpkt (sig, SIGSUBPKT_FEATURES, buf, n);
xfree (buf);
}
static void
add_keyserver_modify (PKT_signature *sig,int enabled)
{
@ -848,6 +893,7 @@ keygen_upd_std_prefs (PKT_signature *sig, void *opaque)
/* Make sure that the MDC feature flag is set if needed. */
add_feature_mdc (sig,mdc_available);
add_feature_aead (sig, aead_available);
add_feature_v5 (sig, opt.flags.rfc4880bis);
add_keyserver_modify (sig,ks_modify);
keygen_add_keyserver_url(sig,NULL);
@ -1370,7 +1416,7 @@ key_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp,
static int
do_create_from_keygrip (ctrl_t ctrl, int algo, const char *hexkeygrip,
kbnode_t pub_root, u32 timestamp, u32 expireval,
int is_subkey)
int is_subkey, int keygen_flags)
{
int err;
PACKET *pkt;
@ -1417,7 +1463,7 @@ do_create_from_keygrip (ctrl_t ctrl, int algo, const char *hexkeygrip,
}
pk->timestamp = timestamp;
pk->version = 4;
pk->version = (keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4;
if (expireval)
pk->expiredate = pk->timestamp + expireval;
pk->pubkey_algo = algo;
@ -1484,7 +1530,7 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
}
pk->timestamp = timestamp;
pk->version = 4;
pk->version = (keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4;
if (expireval)
pk->expiredate = pk->timestamp + expireval;
pk->pubkey_algo = algo;
@ -2928,7 +2974,7 @@ ask_user_id (int mode, int full, KBNODE keyblock)
/* Basic key generation. Here we divert to the actual generation
routines based on the requested algorithm. */
static int
do_create (int algo, unsigned int nbits, const char *curve, KBNODE pub_root,
do_create (int algo, unsigned int nbits, const char *curve, kbnode_t pub_root,
u32 timestamp, u32 expiredate, int is_subkey,
int keygen_flags, const char *passphrase,
char **cache_nonce_addr, char **passwd_nonce_addr)
@ -3007,12 +3053,14 @@ generate_user_id (KBNODE keyblock, const char *uidstr)
* for any parameter. FOR_SUBKEY shall be true if this is used as a
* subkey. If CLEAR_CERT is set a default CERT usage will be cleared;
* this is useful if for example the default algorithm is used for a
* subkey. */
* subkey. If R_KEYVERSION is not NULL it will receive the version of
* the key; this is currently 4 but can be changed with the flag "v5"
* to create a v5 key. */
static gpg_error_t
parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
int *r_algo, unsigned int *r_size,
unsigned int *r_keyuse,
char const **r_curve)
char const **r_curve, int *r_keyversion)
{
char *flags;
int algo;
@ -3021,6 +3069,7 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
int ecdh_or_ecdsa = 0;
unsigned int size;
int keyuse;
int keyversion = 4;
int i;
const char *s;
@ -3119,6 +3168,13 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
return gpg_error (GPG_ERR_INV_FLAG);
}
}
else if (!ascii_strcasecmp (s, "v5"))
{
if (opt.flags.rfc4880bis)
keyversion = 5;
}
else if (!ascii_strcasecmp (s, "v4"))
keyversion = 4;
else
{
xfree (tokens);
@ -3194,10 +3250,13 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
*r_keyuse = keyuse;
if (r_curve)
*r_curve = curve;
if (r_keyversion)
*r_keyversion = keyversion;
return 0;
}
/* Parse and return the standard key generation parameter.
* The string is expected to be in this format:
*
@ -3228,6 +3287,7 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
* ecdsa := Use algorithm ECDSA.
* eddsa := Use algorithm EdDSA.
* ecdh := Use algorithm ECDH.
* v5 := Create version 5 key (requires option --rfc4880bis)
*
* There are several defaults and fallbacks depending on the
* algorithm. PART can be used to select which part of STRING is
@ -3246,9 +3306,11 @@ parse_key_parameter_string (const char *string, int part,
int *r_algo, unsigned int *r_size,
unsigned int *r_keyuse,
char const **r_curve,
int *r_version,
int *r_subalgo, unsigned int *r_subsize,
unsigned *r_subkeyuse,
char const **r_subcurve)
unsigned int *r_subkeyuse,
char const **r_subcurve,
int *r_subversion)
{
gpg_error_t err = 0;
char *primary, *secondary;
@ -3261,6 +3323,8 @@ parse_key_parameter_string (const char *string, int part,
*r_keyuse = 0;
if (r_curve)
*r_curve = NULL;
if (r_version)
*r_version = 4;
if (r_subalgo)
*r_subalgo = 0;
if (r_subsize)
@ -3269,6 +3333,8 @@ parse_key_parameter_string (const char *string, int part,
*r_subkeyuse = 0;
if (r_subcurve)
*r_subcurve = NULL;
if (r_subversion)
*r_subversion = 4;
if (!string || !*string
|| !ascii_strcasecmp (string, "default") || !strcmp (string, "-"))
@ -3283,11 +3349,11 @@ parse_key_parameter_string (const char *string, int part,
*secondary++ = 0;
if (part == -1 || part == 0)
{
err = parse_key_parameter_part (primary, 0, 0, r_algo, r_size,
r_keyuse, r_curve);
err = parse_key_parameter_part (primary, 0, 0, r_algo, r_size,
r_keyuse, r_curve, r_version);
if (!err && part == -1)
err = parse_key_parameter_part (secondary, 1, 0, r_subalgo, r_subsize,
r_subkeyuse, r_subcurve);
r_subkeyuse, r_subcurve, r_subversion);
}
else if (part == 1)
{
@ -3300,14 +3366,17 @@ parse_key_parameter_string (const char *string, int part,
if (secondary)
{
err = parse_key_parameter_part (secondary, 1, 0,
r_algo, r_size, r_keyuse, r_curve);
r_algo, r_size, r_keyuse, r_curve,
r_version);
if (!err && suggested_use && r_keyuse && !(suggested_use & *r_keyuse))
err = parse_key_parameter_part (primary, 1, 1 /*(clear cert)*/,
r_algo, r_size, r_keyuse, r_curve);
r_algo, r_size, r_keyuse, r_curve,
r_version);
}
else
err = parse_key_parameter_part (primary, 1, 0,
r_algo, r_size, r_keyuse, r_curve);
r_algo, r_size, r_keyuse, r_curve,
r_version);
}
xfree (primary);
@ -3395,9 +3464,8 @@ get_parameter_algo( struct para_data_s *para, enum para_name key,
* compatibility with the batch key generation. It would be
* better to make full use of parse_key_parameter_string. */
parse_key_parameter_string (NULL, 0, 0,
&i, NULL, NULL, NULL,
NULL, NULL, NULL, NULL);
&i, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL);
if (r_default)
*r_default = 1;
}
@ -3810,6 +3878,8 @@ read_parameter_file (ctrl_t ctrl, const char *fname )
{ "Keygrip", pKEYGRIP },
{ "Key-Grip", pKEYGRIP },
{ "Subkey-grip", pSUBKEYGRIP },
{ "Key-Version", pVERSION },
{ "Subkey-Version", pSUBVERSION },
{ NULL, 0 }
};
IOBUF fp;
@ -3954,12 +4024,19 @@ read_parameter_file (ctrl_t ctrl, const char *fname )
break;
}
}
r = xmalloc_clear( sizeof *r + strlen( value ) );
r->lnr = lnr;
r->key = keywords[i].key;
strcpy( r->u.value, value );
r->next = para;
para = r;
if (!opt.flags.rfc4880bis && (keywords[i].key == pVERSION
|| keywords[i].key == pSUBVERSION))
; /* Ignore version unless --rfc4880bis is active. */
else
{
r = xmalloc_clear( sizeof *r + strlen( value ) );
r->lnr = lnr;
r->key = keywords[i].key;
strcpy( r->u.value, value );
r->next = para;
para = r;
}
}
if( err )
log_error("%s:%d: %s\n", fname, lnr, err );
@ -3994,7 +4071,8 @@ read_parameter_file (ctrl_t ctrl, const char *fname )
/* Helper for quick_generate_keypair. */
static struct para_data_s *
quickgen_set_para (struct para_data_s *para, int for_subkey,
int algo, int nbits, const char *curve, unsigned int use)
int algo, int nbits, const char *curve, unsigned int use,
int version)
{
struct para_data_s *r;
@ -4033,6 +4111,15 @@ quickgen_set_para (struct para_data_s *para, int for_subkey,
para = r;
}
if (opt.flags.rfc4880bis)
{
r = xmalloc_clear (sizeof *r + 20);
r->key = for_subkey? pSUBVERSION : pVERSION;
snprintf (r->u.value, 20, "%d", version);
r->next = para;
para = r;
}
return para;
}
@ -4125,25 +4212,26 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
|| !strcmp (usagestr, "-")))
{
/* Use default key parameters. */
int algo, subalgo;
int algo, subalgo, version, subversion;
unsigned int size, subsize;
unsigned int keyuse, subkeyuse;
const char *curve, *subcurve;
err = parse_key_parameter_string (algostr, -1, 0,
&algo, &size, &keyuse, &curve,
&algo, &size, &keyuse, &curve, &version,
&subalgo, &subsize, &subkeyuse,
&subcurve);
&subcurve, &subversion);
if (err)
{
log_error (_("Key generation failed: %s\n"), gpg_strerror (err));
goto leave;
}
para = quickgen_set_para (para, 0, algo, size, curve, keyuse);
para = quickgen_set_para (para, 0, algo, size, curve, keyuse, version);
if (subalgo)
para = quickgen_set_para (para, 1,
subalgo, subsize, subcurve, subkeyuse);
subalgo, subsize, subcurve, subkeyuse,
subversion);
if (*expirestr)
{
@ -4166,21 +4254,22 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
else
{
/* Extended unattended mode. Creates only the primary key. */
int algo;
int algo, version;
unsigned int use;
u32 expire;
unsigned int nbits;
const char *curve;
err = parse_algo_usage_expire (ctrl, 0, algostr, usagestr, expirestr,
&algo, &use, &expire, &nbits, &curve);
&algo, &use, &expire, &nbits, &curve,
&version);
if (err)
{
log_error (_("Key generation failed: %s\n"), gpg_strerror (err) );
goto leave;
}
para = quickgen_set_para (para, 0, algo, nbits, curve, use);
para = quickgen_set_para (para, 0, algo, nbits, curve, use, version);
r = xmalloc_clear (sizeof *r + 20);
r->key = pKEYEXPIRE;
r->u.expire = expire;
@ -4494,7 +4583,7 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
}
else /* Default key generation. */
{
int subalgo;
int subalgo, version, subversion;
unsigned int size, subsize;
unsigned int keyuse, subkeyuse;
const char *curve, *subcurve;
@ -4509,18 +4598,19 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
, "--full-generate-key" );
err = parse_key_parameter_string (NULL, -1, 0,
&algo, &size, &keyuse, &curve,
&algo, &size, &keyuse, &curve, &version,
&subalgo, &subsize,
&subkeyuse, &subcurve);
&subkeyuse, &subcurve, &subversion);
if (err)
{
log_error (_("Key generation failed: %s\n"), gpg_strerror (err));
return;
}
para = quickgen_set_para (para, 0, algo, size, curve, keyuse);
para = quickgen_set_para (para, 0, algo, size, curve, keyuse, version);
if (subalgo)
para = quickgen_set_para (para, 1,
subalgo, subsize, subcurve, subkeyuse);
subalgo, subsize, subcurve, subkeyuse,
subversion);
}
@ -4740,6 +4830,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
int algo;
u32 expire;
const char *key_from_hexgrip = NULL;
unsigned int keygen_flags;
if (outctrl->dryrun)
{
@ -4808,9 +4899,14 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
algo = get_parameter_algo( para, pKEYTYPE, NULL );
expire = get_parameter_u32( para, pKEYEXPIRE );
key_from_hexgrip = get_parameter_value (para, pKEYGRIP);
keygen_flags = outctrl->keygen_flags;
if (get_parameter_uint (para, pVERSION) == 5)
keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY;
if (key_from_hexgrip)
err = do_create_from_keygrip (ctrl, algo, key_from_hexgrip,
pub_root, timestamp, expire, 0);
pub_root, timestamp, expire, 0, keygen_flags);
else if (!card)
err = do_create (algo,
get_parameter_uint( para, pKEYLENGTH ),
@ -4818,13 +4914,13 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
pub_root,
timestamp,
expire, 0,
outctrl->keygen_flags,
keygen_flags,
get_parameter_passphrase (para),
&cache_nonce, NULL);
else
err = gen_card_key (1, algo,
1, pub_root, &timestamp,
expire);
expire, keygen_flags);
/* Get the pointer to the generated public key packet. */
if (!err)
@ -4863,7 +4959,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
if (!err && card && get_parameter (para, pAUTHKEYTYPE))
{
err = gen_card_key (3, get_parameter_algo( para, pAUTHKEYTYPE, NULL ),
0, pub_root, &timestamp, expire);
0, pub_root, &timestamp, expire, keygen_flags);
if (!err)
err = write_keybinding (ctrl, pub_root, pri_psk, NULL,
PUBKEY_USAGE_AUTH, timestamp, cache_nonce);
@ -4875,11 +4971,16 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
s = NULL;
key_from_hexgrip = get_parameter_value (para, pSUBKEYGRIP);
keygen_flags = outctrl->keygen_flags;
if (get_parameter_uint (para, pSUBVERSION) == 5)
keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY;
if (key_from_hexgrip)
err = do_create_from_keygrip (ctrl, subkey_algo, key_from_hexgrip,
pub_root, timestamp,
get_parameter_u32 (para, pSUBKEYEXPIRE),
1);
1, keygen_flags);
else if (!card || (s = get_parameter_value (para, pCARDBACKUPKEY)))
{
err = do_create (subkey_algo,
@ -4888,7 +4989,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
pub_root,
timestamp,
get_parameter_u32 (para, pSUBKEYEXPIRE), 1,
s ? KEYGEN_FLAG_NO_PROTECTION : outctrl->keygen_flags,
s? KEYGEN_FLAG_NO_PROTECTION : keygen_flags,
get_parameter_passphrase (para),
&cache_nonce, NULL);
/* Get the pointer to the generated public subkey packet. */
@ -4908,7 +5009,8 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
}
else
{
err = gen_card_key (2, subkey_algo, 0, pub_root, &timestamp, expire);
err = gen_card_key (2, subkey_algo, 0, pub_root, &timestamp, expire,
keygen_flags);
}
if (!err)
@ -5032,13 +5134,15 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
const char *algostr, const char *usagestr,
const char *expirestr,
int *r_algo, unsigned int *r_usage, u32 *r_expire,
unsigned int *r_nbits, const char **r_curve)
unsigned int *r_nbits, const char **r_curve,
int *r_version)
{
gpg_error_t err;
int algo;
unsigned int use, nbits;
u32 expire;
int wantuse;
int version = 4;
const char *curve = NULL;
*r_curve = NULL;
@ -5056,8 +5160,8 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
err = parse_key_parameter_string (algostr, for_subkey? 1 : 0,
usagestr? parse_usagestr (usagestr):0,
&algo, &nbits, &use, &curve,
NULL, NULL, NULL, NULL);
&algo, &nbits, &use, &curve, &version,
NULL, NULL, NULL, NULL, NULL);
if (err)
return err;
@ -5095,6 +5199,7 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
*r_usage = use;
*r_expire = expire;
*r_nbits = nbits;
*r_version = version;
return 0;
}
@ -5122,6 +5227,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
char *serialno = NULL;
char *cache_nonce = NULL;
char *passwd_nonce = NULL;
int keygen_flags = 0;
interactive = (!algostr || !usagestr || !expirestr);
@ -5203,10 +5309,16 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
}
else /* Unattended mode. */
{
int version;
err = parse_algo_usage_expire (ctrl, 1, algostr, usagestr, expirestr,
&algo, &use, &expire, &nbits, &curve);
&algo, &use, &expire, &nbits, &curve,
&version);
if (err)
goto leave;
if (version == 5)
keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY;
}
/* Verify the passphrase now so that we get a cache item for the
@ -5229,7 +5341,8 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
if (key_from_hexgrip)
{
err = do_create_from_keygrip (ctrl, algo, key_from_hexgrip,
keyblock, cur_time, expire, 1);
keyblock, cur_time, expire, 1,
keygen_flags);
}
else
{
@ -5245,7 +5358,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
passwd = NULL;
err = do_create (algo, nbits, curve,
keyblock, cur_time, expire, 1, 0,
keyblock, cur_time, expire, 1, keygen_flags,
passwd, &cache_nonce, &passwd_nonce);
}
if (err)
@ -5293,6 +5406,7 @@ generate_card_subkeypair (ctrl_t ctrl, kbnode_t pub_keyblock,
PKT_public_key *sub_pk = NULL;
int algo;
struct agent_card_info_s info;
int keygen_flags = 0; /* FIXME!!! */
log_assert (keyno >= 1 && keyno <= 3);
@ -5363,7 +5477,8 @@ generate_card_subkeypair (ctrl_t ctrl, kbnode_t pub_keyblock,
/* Note, that depending on the backend, the card key generation may
update CUR_TIME. */
err = gen_card_key (keyno, algo, 0, pub_keyblock, &cur_time, expire);
err = gen_card_key (keyno, algo, 0, pub_keyblock, &cur_time, expire,
keygen_flags);
/* Get the pointer to the generated public subkey packet. */
if (!err)
{
@ -5409,10 +5524,11 @@ write_keyblock( IOBUF out, KBNODE node )
}
/* Note that timestamp is an in/out arg. */
/* Note that timestamp is an in/out arg.
* FIXME: Does not yet support v5 keys. */
static gpg_error_t
gen_card_key (int keyno, int algo, int is_primary, kbnode_t pub_root,
u32 *timestamp, u32 expireval)
u32 *timestamp, u32 expireval, int keygen_flags)
{
#ifdef ENABLE_CARD_SUPPORT
gpg_error_t err;
@ -5486,7 +5602,7 @@ gen_card_key (int keyno, int algo, int is_primary, kbnode_t pub_root,
}
pk->timestamp = *timestamp;
pk->version = 4;
pk->version = (keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4;
if (expireval)
pk->expiredate = pk->timestamp + expireval;
pk->pubkey_algo = algo;

View File

@ -136,19 +136,21 @@ pubkey_string (PKT_public_key *pk, char *buffer, size_t bufsize)
}
/* Hash a public key. This function is useful for v4 fingerprints and
for v3 or v4 key signing. */
/* 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)
{
unsigned int n = 6;
unsigned int n;
unsigned int nn[PUBKEY_MAX_NPKEY];
byte *pp[PUBKEY_MAX_NPKEY];
int i;
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;
/* 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
@ -201,12 +203,22 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk)
}
}
gcry_md_putc ( md, 0x99 ); /* ctb */
/* What does it mean if n is greater than 0xFFFF ? */
gcry_md_putc ( md, n >> 8 ); /* 2 byte length header */
gcry_md_putc ( md, n );
gcry_md_putc ( md, pk->version );
if (is_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 );
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, pk->timestamp >> 24 );
gcry_md_putc ( md, pk->timestamp >> 16 );
gcry_md_putc ( md, pk->timestamp >> 8 );
@ -214,6 +226,15 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk)
gcry_md_putc ( md, pk->pubkey_algo );
if (is_v5)
{
n -= 10;
gcry_md_putc ( md, n >> 24 );
gcry_md_putc ( md, n >> 16 );
gcry_md_putc ( md, n >> 8 );
gcry_md_putc ( md, n );
}
if(npkey==0 && pk->pkey[0]
&& gcry_mpi_get_flag (pk->pkey[0], GCRYMPI_FLAG_OPAQUE))
{
@ -237,10 +258,10 @@ do_fingerprint_md( PKT_public_key *pk )
{
gcry_md_hd_t md;
if (gcry_md_open (&md, DIGEST_ALGO_SHA1, 0))
if (gcry_md_open (&md, pk->version == 5 ? GCRY_MD_SHA256 : GCRY_MD_SHA1, 0))
BUG ();
hash_public_key(md,pk);
gcry_md_final( md );
hash_public_key (md,pk);
gcry_md_final (md);
return md;
}
@ -517,13 +538,12 @@ keystr_from_desc(KEYDB_SEARCH_DESC *desc)
/*
* Get the keyid from the public key and put it into keyid
* if this is not NULL. Return the 32 low bits of the keyid.
* Get the keyid from the public key PK and store it at KEYID unless
* this is NULL. Returns the 32 bit short keyid.
*/
u32
keyid_from_pk (PKT_public_key *pk, u32 *keyid)
{
u32 lowbits;
u32 dummy_keyid[2];
if (!keyid)
@ -533,7 +553,6 @@ keyid_from_pk (PKT_public_key *pk, u32 *keyid)
{
keyid[0] = pk->keyid[0];
keyid[1] = pk->keyid[1];
lowbits = keyid[1];
}
else
{
@ -544,18 +563,25 @@ keyid_from_pk (PKT_public_key *pk, u32 *keyid)
if(md)
{
dp = gcry_md_read ( md, 0 );
keyid[0] = buf32_to_u32 (dp+12);
keyid[1] = buf32_to_u32 (dp+16);
lowbits = keyid[1];
if (pk->version == 5)
{
keyid[0] = buf32_to_u32 (dp);
keyid[1] = buf32_to_u32 (dp+4);
}
else
{
keyid[0] = buf32_to_u32 (dp+12);
keyid[1] = buf32_to_u32 (dp+16);
}
gcry_md_close (md);
pk->keyid[0] = keyid[0];
pk->keyid[1] = keyid[1];
}
else
pk->keyid[0]=pk->keyid[1]=keyid[0]=keyid[1]=lowbits=0xFFFFFFFF;
pk->keyid[0] = pk->keyid[1] = keyid[0]= keyid[1] = 0xFFFFFFFF;
}
return lowbits;
return keyid[1]; /*FIXME:shortkeyid ist different for v5*/
}
@ -594,8 +620,16 @@ keyid_from_fingerprint (ctrl_t ctrl, const byte *fprint,
else
{
const byte *dp = fprint;
keyid[0] = buf32_to_u32 (dp+12);
keyid[1] = buf32_to_u32 (dp+16);
if (fprint_len == 20) /* v4 key */
{
keyid[0] = buf32_to_u32 (dp+12);
keyid[1] = buf32_to_u32 (dp+16);
}
else /* v5 key */
{
keyid[0] = buf32_to_u32 (dp);
keyid[1] = buf32_to_u32 (dp+4);
}
}
return keyid[1];
@ -610,7 +644,7 @@ keyid_from_sig (PKT_signature *sig, u32 *keyid)
keyid[0] = sig->keyid[0];
keyid[1] = sig->keyid[1];
}
return sig->keyid[1];
return sig->keyid[1]; /*FIXME:shortkeyid*/
}
@ -800,15 +834,23 @@ fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len)
size_t len;
gcry_md_hd_t md;
md = do_fingerprint_md(pk);
dp = gcry_md_read( md, 0 );
md = do_fingerprint_md (pk);
dp = gcry_md_read (md, 0);
len = gcry_md_get_algo_dlen (gcry_md_get_algo (md));
log_assert( len <= MAX_FINGERPRINT_LEN );
log_assert (len <= MAX_FINGERPRINT_LEN);
if (!array)
array = xmalloc ( len );
memcpy (array, dp, len );
pk->keyid[0] = buf32_to_u32 (dp+12);
pk->keyid[1] = buf32_to_u32 (dp+16);
if (pk->version == 5)
{
pk->keyid[0] = buf32_to_u32 (dp);
pk->keyid[1] = buf32_to_u32 (dp+4);
}
else
{
pk->keyid[0] = buf32_to_u32 (dp+12);
pk->keyid[1] = buf32_to_u32 (dp+16);
}
gcry_md_close( md);
if (ret_len)

View File

@ -829,6 +829,8 @@ proc_plaintext( CTX c, PACKET *pkt )
PKT_plaintext *pt = pkt->pkt.plaintext;
int any, clearsig, rc;
kbnode_t n;
unsigned char *extrahash;
size_t extrahashlen;
/* This is a literal data packet. Bump a counter for later checks. */
literals_seen++;
@ -948,8 +950,33 @@ proc_plaintext( CTX c, PACKET *pkt )
c->last_was_session_key = 0;
/* We add a marker control packet instead of the plaintext packet.
* This is so that we can later detect invalid packet sequences. */
n = new_kbnode (create_gpg_control (CTRLPKT_PLAINTEXT_MARK, NULL, 0));
* This is so that we can later detect invalid packet sequences.
* The apcket is further used to convey extra data from the
* plaintext packet to the signature verification. */
extrahash = xtrymalloc (6 + pt->namelen);
if (!extrahash)
{
/* No way to return an error. */
rc = gpg_error_from_syserror ();
log_error ("malloc failed in %s: %s\n", __func__, gpg_strerror (rc));
extrahashlen = 0;
}
else
{
extrahash[0] = pt->mode;
extrahash[1] = pt->namelen;
if (pt->namelen)
memcpy (extrahash+2, pt->name, pt->namelen);
extrahashlen = 2 + pt->namelen;
extrahash[extrahashlen++] = pt->timestamp >> 24;
extrahash[extrahashlen++] = pt->timestamp >> 16;
extrahash[extrahashlen++] = pt->timestamp >> 8;
extrahash[extrahashlen++] = pt->timestamp ;
}
n = new_kbnode (create_gpg_control (CTRLPKT_PLAINTEXT_MARK,
extrahash, extrahashlen));
xfree (extrahash);
if (c->list)
add_kbnode (c->list, n);
else
@ -1019,7 +1046,8 @@ proc_compressed (CTX c, PACKET *pkt)
* found. Returns: 0 = valid signature or an error code
*/
static int
do_check_sig (CTX c, kbnode_t node, int *is_selfsig,
do_check_sig (CTX c, kbnode_t node, const void *extrahash, size_t extrahashlen,
int *is_selfsig,
int *is_expkey, int *is_revkey, PKT_public_key **r_pk)
{
PKT_signature *sig;
@ -1105,14 +1133,16 @@ do_check_sig (CTX c, kbnode_t node, int *is_selfsig,
/* We only get here if we are checking the signature of a binary
(0x00) or text document (0x01). */
rc = check_signature2 (c->ctrl, sig, md, NULL, is_expkey, is_revkey, r_pk);
rc = check_signature2 (c->ctrl, sig, md, extrahash, extrahashlen,
NULL, is_expkey, is_revkey, r_pk);
if (! rc)
md_good = md;
else if (gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE && md2)
{
PKT_public_key *pk2;
rc = check_signature2 (c->ctrl, sig, md2, NULL, is_expkey, is_revkey,
rc = check_signature2 (c->ctrl, sig, md2, extrahash, extrahashlen,
NULL, is_expkey, is_revkey,
r_pk? &pk2 : NULL);
if (!rc)
{
@ -1275,7 +1305,7 @@ list_node (CTX c, kbnode_t node)
if (opt.check_sigs)
{
fflush (stdout);
rc2 = do_check_sig (c, node, &is_selfsig, NULL, NULL, NULL);
rc2 = do_check_sig (c, node, NULL, 0, &is_selfsig, NULL, NULL, NULL);
switch (gpg_err_code (rc2))
{
case 0: sigrc = '!'; break;
@ -1738,7 +1768,7 @@ akl_has_wkd_method (void)
}
/* Return the ISSUER fingerprint buffer and its lenbgth at R_LEN.
/* Return the ISSUER fingerprint buffer and its length at R_LEN.
* Returns NULL if not available. The returned buffer is valid as
* long as SIG is not modified. */
const byte *
@ -1748,7 +1778,7 @@ issuer_fpr_raw (PKT_signature *sig, size_t *r_len)
size_t n;
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_ISSUER_FPR, &n);
if (p && n == 21 && p[0] == 4)
if (p && ((n == 21 && p[0] == 4) || (n == 33 && p[0] == 5)))
{
*r_len = n - 1;
return p+1;
@ -1811,6 +1841,8 @@ check_sig_and_print (CTX c, kbnode_t node)
char *issuer_fpr = NULL;
PKT_public_key *pk = NULL; /* The public key for the signature or NULL. */
int tried_ks_by_fpr;
const void *extrahash = NULL;
size_t extrahashlen = 0;
if (opt.skip_verify)
{
@ -1868,6 +1900,8 @@ check_sig_and_print (CTX c, kbnode_t node)
{
if (n->next)
goto ambiguous; /* We only allow one P packet. */
extrahash = n->pkt->pkt.gpg_control->data;
extrahashlen = n->pkt->pkt.gpg_control->datalen;
}
else
goto ambiguous;
@ -1882,6 +1916,9 @@ check_sig_and_print (CTX c, kbnode_t node)
&& (n->pkt->pkt.gpg_control->control
== CTRLPKT_PLAINTEXT_MARK)))
goto ambiguous;
extrahash = n->pkt->pkt.gpg_control->data;
extrahashlen = n->pkt->pkt.gpg_control->datalen;
for (n_sig=0, n = n->next;
n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next)
n_sig++;
@ -1912,6 +1949,8 @@ check_sig_and_print (CTX c, kbnode_t node)
&& (n->pkt->pkt.gpg_control->control
== CTRLPKT_PLAINTEXT_MARK)))
goto ambiguous;
extrahash = n->pkt->pkt.gpg_control->data;
extrahashlen = n->pkt->pkt.gpg_control->datalen;
for (n_sig=0, n = n->next;
n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next)
n_sig++;
@ -1957,7 +1996,8 @@ check_sig_and_print (CTX c, kbnode_t node)
if (sig->signers_uid)
log_info (_(" issuer \"%s\"\n"), sig->signers_uid);
rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk);
rc = do_check_sig (c, node, extrahash, extrahashlen,
NULL, &is_expkey, &is_revkey, &pk);
/* If the key isn't found, check for a preferred keyserver. */
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && sig->flags.pref_ks)
@ -1992,8 +2032,8 @@ check_sig_and_print (CTX c, kbnode_t node)
res = keyserver_import_keyid (c->ctrl, sig->keyid,spec, 1);
glo_ctrl.in_auto_key_retrieve--;
if (!res)
rc = do_check_sig (c, node, NULL,
&is_expkey, &is_revkey, &pk);
rc = do_check_sig (c, node, extrahash, extrahashlen,
NULL, &is_expkey, &is_revkey, &pk);
free_keyserver_spec (spec);
if (!rc)
@ -2028,7 +2068,8 @@ check_sig_and_print (CTX c, kbnode_t node)
glo_ctrl.in_auto_key_retrieve--;
free_keyserver_spec (spec);
if (!res)
rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk);
rc = do_check_sig (c, node, extrahash, extrahashlen,
NULL, &is_expkey, &is_revkey, &pk);
}
}
}
@ -2050,7 +2091,7 @@ check_sig_and_print (CTX c, kbnode_t node)
p = issuer_fpr_raw (sig, &n);
if (p)
{
/* v4 packet with a SHA-1 fingerprint. */
/* v4 or v5 packet with a SHA-1/256 fingerprint. */
free_public_key (pk);
pk = NULL;
glo_ctrl.in_auto_key_retrieve++;
@ -2058,7 +2099,8 @@ check_sig_and_print (CTX c, kbnode_t node)
tried_ks_by_fpr = 1;
glo_ctrl.in_auto_key_retrieve--;
if (!res)
rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk);
rc = do_check_sig (c, node, extrahash, extrahashlen,
NULL, &is_expkey, &is_revkey, &pk);
}
}
@ -2080,7 +2122,8 @@ check_sig_and_print (CTX c, kbnode_t node)
/* Fixme: If the fingerprint is embedded in the signature,
* compare it to the fingerprint of the returned key. */
if (!res)
rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk);
rc = do_check_sig (c, node, extrahash, extrahashlen,
NULL, &is_expkey, &is_revkey, &pk);
}
/* If the above methods did't work, our next try is to use a
@ -2098,7 +2141,8 @@ check_sig_and_print (CTX c, kbnode_t node)
res = keyserver_import_keyid (c->ctrl, sig->keyid, opt.keyserver, 1);
glo_ctrl.in_auto_key_retrieve--;
if (!res)
rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk);
rc = do_check_sig (c, node, extrahash, extrahashlen,
NULL, &is_expkey, &is_revkey, &pk);
}
if (!rc || gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE)

View File

@ -853,7 +853,7 @@ PACKET *create_gpg_control ( ctrlpkttype_t type,
/*-- build-packet.c --*/
int build_packet (iobuf_t out, PACKET *pkt);
gpg_error_t build_packet_and_meta (iobuf_t out, PACKET *pkt);
gpg_error_t gpg_mpi_write (iobuf_t out, gcry_mpi_t a);
gpg_error_t gpg_mpi_write (iobuf_t out, gcry_mpi_t a, unsigned int *t_nwritten);
gpg_error_t gpg_mpi_write_nohdr (iobuf_t out, gcry_mpi_t a);
u32 calc_packet_length( PACKET *pkt );
void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
@ -900,6 +900,7 @@ int check_signature (ctrl_t ctrl, PKT_signature *sig, gcry_md_hd_t digest);
* it and verifying the signature. */
gpg_error_t check_signature2 (ctrl_t ctrl,
PKT_signature *sig, gcry_md_hd_t digest,
const void *extrahash, size_t extrahashlen,
u32 *r_expiredate, int *r_expired, int *r_revoked,
PKT_public_key **r_pk);

View File

@ -1644,7 +1644,7 @@ parse_one_sig_subpkt (const byte * buffer, size_t n, int type)
if (n < 8)
break;
return 0;
case SIGSUBPKT_ISSUER_FPR: /* issuer key ID */
case SIGSUBPKT_ISSUER_FPR: /* issuer key fingerprint */
if (n < 21)
break;
return 0;
@ -2078,10 +2078,23 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
&& opt.verbose)
log_info ("signature packet without timestamp\n");
p = parse_sig_subpkt2 (sig, SIGSUBPKT_ISSUER);
if (p)
{
sig->keyid[0] = buf32_to_u32 (p);
/* Set the key id. We first try the issuer fingerprint and if
* it is a v4 signature the fallback to the issuer. Note that
* only the issuer packet is also searched in the unhashed area. */
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_ISSUER_FPR, &len);
if (p && len == 21 && p[0] == 4)
{
sig->keyid[0] = buf32_to_u32 (p + 1 + 12);
sig->keyid[1] = buf32_to_u32 (p + 1 + 16);
}
else if (p && len == 33 && p[0] == 5)
{
sig->keyid[0] = buf32_to_u32 (p + 1 );
sig->keyid[1] = buf32_to_u32 (p + 1 + 4);
}
else if ((p = parse_sig_subpkt2 (sig, SIGSUBPKT_ISSUER)))
{
sig->keyid[0] = buf32_to_u32 (p);
sig->keyid[1] = buf32_to_u32 (p + 4);
}
else if (!(sig->pubkey_algo >= 100 && sig->pubkey_algo <= 110)
@ -2287,6 +2300,9 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
int npkey, nskey;
u32 keyid[2];
PKT_public_key *pk;
int is_v5;
unsigned int pkbytes; /* For v5 keys: Number of bytes in the public
* key material. For v4 keys: 0. */
(void) hdr;
@ -2318,12 +2334,13 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
return 0;
}
else if (version == 4)
{
/* The only supported version. Use an older gpg
version (i.e. gpg 1.4) to parse v3 packets. */
}
is_v5 = 0;
else if (version == 5)
is_v5 = 1;
else if (version == 2 || version == 3)
{
/* Not anymore supported since 2.1. Use an older gpg version
* (i.e. gpg 1.4) to parse v3 packets. */
if (opt.verbose > 1)
log_info ("packet(%d) with obsolete version %d\n", pkttype, version);
if (list_mode)
@ -2341,7 +2358,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
goto leave;
}
if (pktlen < 11)
if (pktlen < (is_v5? 15:11))
{
log_error ("packet(%d) too short\n", pkttype);
if (list_mode)
@ -2364,14 +2381,28 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
max_expiredate = 0;
algorithm = iobuf_get_noeof (inp);
pktlen--;
if (is_v5)
{
pkbytes = read_32 (inp);
pktlen -= 4;
}
else
pkbytes = 0;
if (list_mode)
es_fprintf (listfp, ":%s key packet:\n"
"\tversion %d, algo %d, created %lu, expires %lu\n",
pkttype == PKT_PUBLIC_KEY ? "public" :
pkttype == PKT_SECRET_KEY ? "secret" :
pkttype == PKT_PUBLIC_SUBKEY ? "public sub" :
pkttype == PKT_SECRET_SUBKEY ? "secret sub" : "??",
version, algorithm, timestamp, expiredate);
{
es_fprintf (listfp, ":%s key packet:\n"
"\tversion %d, algo %d, created %lu, expires %lu",
pkttype == PKT_PUBLIC_KEY ? "public" :
pkttype == PKT_SECRET_KEY ? "secret" :
pkttype == PKT_PUBLIC_SUBKEY ? "public sub" :
pkttype == PKT_SECRET_SUBKEY ? "secret sub" : "??",
version, algorithm, timestamp, expiredate);
if (is_v5)
es_fprintf (listfp, ", pkbytes %u\n", pkbytes);
else
es_fprintf (listfp, "\n");
}
pk->timestamp = timestamp;
pk->expiredate = expiredate;
@ -2446,6 +2477,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
struct seckey_info *ski;
byte temp[16];
size_t snlen = 0;
unsigned int skbytes;
if (pktlen < 1)
{
@ -2462,23 +2494,42 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
ski->algo = iobuf_get_noeof (inp);
pktlen--;
if (is_v5)
{
unsigned int protcount = 0;
/* Read the one octet count of the following key-protection
* material. Only required in case of unknown values. */
if (!pktlen)
{
err = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
protcount = iobuf_get_noeof (inp);
pktlen--;
if (list_mode)
es_fprintf (listfp, "\tprotbytes: %u\n", protcount);
}
if (ski->algo)
{
ski->is_protected = 1;
ski->s2k.count = 0;
if (ski->algo == 254 || ski->algo == 255)
{
if (pktlen < 3)
if (pktlen < 3)
{
err = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
ski->sha1chk = (ski->algo == 254);
ski->sha1chk = (ski->algo == 254);
ski->algo = iobuf_get_noeof (inp);
pktlen--;
/* Note that a ski->algo > 110 is illegal, but I'm not
erroring on it here as otherwise there would be no
way to delete such a key. */
* erroring out here as otherwise there would be no way
* to delete such a key. */
ski->s2k.mode = iobuf_get_noeof (inp);
pktlen--;
ski->s2k.hash_algo = iobuf_get_noeof (inp);
@ -2504,10 +2555,8 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
}
/* Read the salt. */
switch (ski->s2k.mode)
if (ski->s2k.mode == 3 || ski->s2k.mode == 1)
{
case 1:
case 3:
for (i = 0; i < 8 && pktlen; i++, pktlen--)
temp[i] = iobuf_get_noeof (inp);
if (i < 8)
@ -2516,7 +2565,6 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
goto leave;
}
memcpy (ski->s2k.salt, temp, 8);
break;
}
/* Check the mode. */
@ -2616,7 +2664,9 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
* ski->ivlen = cipher_get_blocksize (ski->algo);
* won't work. The only solution I see is to hardwire it.
* NOTE: if you change the ivlen above 16, don't forget to
* enlarge temp. */
* enlarge temp.
* FIXME: For v5 keys we can deduce this info!
*/
ski->ivlen = openpgp_cipher_blocklen (ski->algo);
log_assert (ski->ivlen <= sizeof (temp));
@ -2644,6 +2694,20 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
memcpy (ski->iv, temp, ski->ivlen);
}
/* Skip count of secret key material. */
if (is_v5)
{
if (pktlen < 4)
{
err = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
skbytes = read_32 (inp);
pktlen -= 4;
if (list_mode)
es_fprintf (listfp, "\tskbytes: %u\n", skbytes);
}
/* It does not make sense to read it into secure memory.
* If the user is so careless, not to protect his secret key,
* we can assume, that he operates an open system :=(.
@ -2666,13 +2730,14 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
/* Ugly: The length is encrypted too, so we read all stuff
* up to the end of the packet into the first SKEY
* element. */
* element.
* FIXME: We can do better for v5 keys. */
pk->pkey[npkey] = gcry_mpi_set_opaque (NULL,
read_rest (inp, pktlen),
pktlen * 8);
/* Mark that MPI as protected - we need this information for
importing a key. The OPAQUE flag can't be used because
we also store public EdDSA values in opaque MPIs. */
* importing a key. The OPAQUE flag can't be used because
* we also store public EdDSA values in opaque MPIs. */
if (pk->pkey[npkey])
gcry_mpi_set_flag (pk->pkey[npkey], GCRYMPI_FLAG_USER1);
pktlen = 0;
@ -3509,11 +3574,13 @@ create_gpg_control (ctrlpkttype_t type, const byte * data, size_t datalen)
PACKET *packet;
byte *p;
if (!data)
datalen = 0;
packet = xmalloc (sizeof *packet);
init_packet (packet);
packet->pkttype = PKT_GPG_CONTROL;
packet->pkt.gpg_control = xmalloc (sizeof *packet->pkt.gpg_control
+ datalen - 1);
packet->pkt.gpg_control = xmalloc (sizeof *packet->pkt.gpg_control + datalen);
packet->pkt.gpg_control->control = type;
packet->pkt.gpg_control->datalen = datalen;
p = packet->pkt.gpg_control->data;

View File

@ -37,11 +37,14 @@
static int check_signature_end (PKT_public_key *pk, PKT_signature *sig,
gcry_md_hd_t digest,
const void *extrahash, size_t extrahashlen,
int *r_expired, int *r_revoked,
PKT_public_key *ret_pk);
static int check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig,
gcry_md_hd_t digest);
gcry_md_hd_t digest,
const void *extrahash,
size_t extrahashlen);
/* Statistics for signature verification. */
@ -69,7 +72,7 @@ sig_check_dump_stats (void)
int
check_signature (ctrl_t ctrl, PKT_signature *sig, gcry_md_hd_t digest)
{
return check_signature2 (ctrl, sig, digest, NULL, NULL, NULL, NULL);
return check_signature2 (ctrl, sig, digest, NULL, 0, NULL, NULL, NULL, NULL);
}
@ -95,6 +98,9 @@ check_signature (ctrl_t ctrl, PKT_signature *sig, gcry_md_hd_t digest)
* signature data from the version number through the hashed subpacket
* data (inclusive) is hashed.")
*
* EXTRAHASH and EXTRAHASHLEN is additional data which is hashed with
* v5 signatures. They may be NULL to use the default.
*
* If R_EXPIREDATE is not NULL, R_EXPIREDATE is set to the key's
* expiry.
*
@ -112,7 +118,9 @@ check_signature (ctrl_t ctrl, PKT_signature *sig, gcry_md_hd_t digest)
* Returns 0 on success. An error code otherwise. */
gpg_error_t
check_signature2 (ctrl_t ctrl,
PKT_signature *sig, gcry_md_hd_t digest, u32 *r_expiredate,
PKT_signature *sig, gcry_md_hd_t digest,
const void *extrahash, size_t extrahashlen,
u32 *r_expiredate,
int *r_expired, int *r_revoked, PKT_public_key **r_pk)
{
int rc=0;
@ -179,7 +187,8 @@ check_signature2 (ctrl_t ctrl,
if (r_expiredate)
*r_expiredate = pk->expiredate;
rc = check_signature_end (pk, sig, digest, r_expired, r_revoked, NULL);
rc = check_signature_end (pk, sig, digest, extrahash, extrahashlen,
r_expired, r_revoked, NULL);
/* Check the backsig. This is a back signature (0x19) from
* the subkey on the primary key. The idea here is that it
@ -424,6 +433,7 @@ check_signature_metadata_validity (PKT_public_key *pk, PKT_signature *sig,
static int
check_signature_end (PKT_public_key *pk, PKT_signature *sig,
gcry_md_hd_t digest,
const void *extrahash, size_t extrahashlen,
int *r_expired, int *r_revoked, PKT_public_key *ret_pk)
{
int rc = 0;
@ -432,7 +442,8 @@ check_signature_end (PKT_public_key *pk, PKT_signature *sig,
r_expired, r_revoked)))
return rc;
if ((rc = check_signature_end_simple (pk, sig, digest)))
if ((rc = check_signature_end_simple (pk, sig, digest,
extrahash, extrahashlen)))
return rc;
if (!rc && ret_pk)
@ -447,7 +458,8 @@ check_signature_end (PKT_public_key *pk, PKT_signature *sig,
* expiration, revocation, etc. */
static int
check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig,
gcry_md_hd_t digest)
gcry_md_hd_t digest,
const void *extrahash, size_t extrahashlen)
{
gcry_mpi_t result = NULL;
int rc = 0;
@ -539,8 +551,13 @@ check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig,
/* - One octet content format
* - File name (one octet length followed by the name)
* - Four octet timestamp */
memset (buf, 0, 6);
gcry_md_write (digest, buf, 6);
if (extrahash && extrahashlen)
gcry_md_write (digest, extrahash, extrahashlen);
else /* Detached signature. */
{
memset (buf, 0, 6);
gcry_md_write (digest, buf, 6);
}
}
/* Add some magic per Section 5.2.4 of RFC 4880. */
i = 0;
@ -790,7 +807,7 @@ check_backsig (PKT_public_key *main_pk,PKT_public_key *sub_pk,
{
hash_public_key(md,main_pk);
hash_public_key(md,sub_pk);
rc = check_signature_end (sub_pk, backsig, md, NULL, NULL, NULL);
rc = check_signature_end (sub_pk, backsig, md, NULL, 0, NULL, NULL, NULL);
cache_sig_result(backsig,rc);
gcry_md_close(md);
}
@ -977,28 +994,28 @@ check_signature_over_key_or_uid (ctrl_t ctrl, PKT_public_key *signer,
{
log_assert (packet->pkttype == PKT_PUBLIC_KEY);
hash_public_key (md, packet->pkt.public_key);
rc = check_signature_end_simple (signer, sig, md);
rc = check_signature_end_simple (signer, sig, md, NULL, 0);
}
else if (IS_BACK_SIG (sig))
{
log_assert (packet->pkttype == PKT_PUBLIC_KEY);
hash_public_key (md, packet->pkt.public_key);
hash_public_key (md, signer);
rc = check_signature_end_simple (signer, sig, md);
rc = check_signature_end_simple (signer, sig, md, NULL, 0);
}
else if (IS_SUBKEY_SIG (sig) || IS_SUBKEY_REV (sig))
{
log_assert (packet->pkttype == PKT_PUBLIC_SUBKEY);
hash_public_key (md, pripk);
hash_public_key (md, packet->pkt.public_key);
rc = check_signature_end_simple (signer, sig, md);
rc = check_signature_end_simple (signer, sig, md, NULL, 0);
}
else if (IS_UID_SIG (sig) || IS_UID_REV (sig))
{
log_assert (packet->pkttype == PKT_USER_ID);
hash_public_key (md, pripk);
hash_uid_packet (packet->pkt.user_id, md, sig);
rc = check_signature_end_simple (signer, sig, md);
rc = check_signature_end_simple (signer, sig, md, NULL, 0);
}
else
{

View File

@ -49,6 +49,10 @@
#define LF "\n"
#endif
/* Hack */
static int recipient_digest_algo;
/* A type for the extra data we hash into v5 signature packets. */
struct pt_extra_hash_data_s
{
@ -60,10 +64,6 @@ struct pt_extra_hash_data_s
typedef struct pt_extra_hash_data_s *pt_extra_hash_data_t;
/* Hack */
static int recipient_digest_algo;
/*
* Create notations and other stuff. It is assumed that the strings in
* STRLIST are already checked to contain only printable data and have
@ -746,8 +746,8 @@ write_plaintext_packet (iobuf_t out, iobuf_t inp,
(*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. */
/* Note that the last byte of NAME won't be initialized
* because we don't need it. */
memcpy ((*r_extrahash)->name, pt->name, pt->namelen);
}
pt->buf = NULL;