aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--g10/build-packet.c167
-rw-r--r--g10/keygen.c232
-rw-r--r--g10/keyid.c100
-rw-r--r--g10/mainproc.c76
-rw-r--r--g10/packet.h3
-rw-r--r--g10/parse-packet.c129
-rw-r--r--g10/sig-check.c43
-rw-r--r--g10/sign.c12
8 files changed, 565 insertions, 197 deletions
diff --git a/g10/build-packet.c b/g10/build-packet.c
index dd4ad54bf..07fccb099 100644
--- a/g10/build-packet.c
+++ b/g10/build-packet.c
@@ -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();
+
+ /* Note that the Version number, Timestamp, Algo, and the v5 Key
+ * material count are written at the end of the function. */
- iobuf_put (a, pk->pubkey_algo );
+ 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)
{
diff --git a/g10/keygen.c b/g10/keygen.c
index 61f839a9f..64fefd231 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -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);
@@ -761,6 +764,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)
{
const byte *s;
@@ -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;
diff --git a/g10/keyid.c b/g10/keyid.c
index 9558a2617..92be95944 100644
--- a/g10/keyid.c
+++ b/g10/keyid.c
@@ -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)
diff --git a/g10/mainproc.c b/g10/mainproc.c
index 8c41088cc..6fa30e0d4 100644
--- a/g10/mainproc.c
+++ b/g10/mainproc.c
@@ -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)
diff --git a/g10/packet.h b/g10/packet.h
index 6160d0b01..41dd1a95a 100644
--- a/g10/packet.h
+++ b/g10/packet.h
@@ -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);
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index 21a26c786..5b4b1c900 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -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;
diff --git a/g10/sig-check.c b/g10/sig-check.c
index e8782f90d..e7f97de65 100644
--- a/g10/sig-check.c
+++ b/g10/sig-check.c
@@ -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
{
diff --git a/g10/sign.c b/g10/sign.c
index 67556d8ba..176940bff 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -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;