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(); - 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) { 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); @@ -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, ×tamp, - 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, ×tamp, expire); + 0, pub_root, ×tamp, 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, ×tamp, expire); + err = gen_card_key (2, subkey_algo, 0, pub_root, ×tamp, 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;