mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-03 12:11:33 +01:00
gpg: Implement v5 keys and v5 signatures.
* g10/build-packet.c (gpg_mpi_write): New optional arg R_NWRITTEN. Allow NULL for OUT. Change all callers. (do_key): Support v5 keys. (build_sig_subpkt_from_sig): Support 32 byte fingerprints. * g10/parse-packet.c (parse_signature): First try to set the keyid from the issuer fingerprint. (parse_key): Support v5 keys. (create_gpg_control): Better make sure to always allocate the static size of the struct in case future compilers print warnings. * g10/keyid.c (hash_public_key): Add v5 support. (keyid_from_pk): Ditto. (keyid_from_fingerprint): Ditto. (fingerprint_from_pk): Ditto. * g10/keygen.c (KEYGEN_FLAG_CREATE_V5_KEY): New. (pVERSION, pSUBVERSION): New. (add_feature_v5): New. (keygen_upd_std_prefs): Call it. (do_create_from_keygrip): Add arg keygen_flags and support the v5 flag. (common_gen): Support the v5 flag. (parse_key_parameter_part): New flags v4 and v5. (parse_key_parameter_string): Add args for version and subversion. (read_parameter_file): New keywords "Key-Version" and "Subkey-Version". (quickgen_set_para): Add arg 'version'. (quick_generate_keypair, generate_keypair): Support version parms. (do_generate_keypair): Support v5 key flag. (generate_subkeypair): Ditto. (generate_card_subkeypair): Preparse for keyflags. (gen_card_key): Ditto. * g10/sig-check.c (check_signature2): Add args extrahash and extrahashlen. (check_signature_end): Ditto. (check_signature_end_simple): Ditto. Use them. * g10/mainproc.c (proc_plaintext): Put extra hash infor into the control packet. (do_check_sig): Add args extrahas and extrahashlen and pass them on. (issuer_fpr_raw): Support 32 byte fingerprint. (check_sig_and_print): get extra hash data and pass it on. -- Note that this is only basic support and requires more fine tuning/fixing. Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
f40e9d6a52
commit
01c87d4ce2
@ -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_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))
|
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); */
|
/* gcry_log_debughex (" ", p, (nbits+7)/8); */
|
||||||
lenhdr[0] = nbits >> 8;
|
lenhdr[0] = nbits >> 8;
|
||||||
lenhdr[1] = nbits;
|
lenhdr[1] = nbits;
|
||||||
rc = iobuf_write (out, lenhdr, 2);
|
err = out? iobuf_write (out, lenhdr, 2) : 0;
|
||||||
if (!rc && p)
|
if (!err)
|
||||||
rc = iobuf_write (out, p, (nbits+7)/8);
|
{
|
||||||
|
nwritten += 2;
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
err = out? iobuf_write (out, p, (nbits+7)/8) : 0;
|
||||||
|
if (!err)
|
||||||
|
nwritten += (nbits+7)/8;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -287,18 +298,25 @@ gpg_mpi_write (iobuf_t out, gcry_mpi_t a)
|
|||||||
size_t nbytes;
|
size_t nbytes;
|
||||||
|
|
||||||
nbytes = DIM(buffer);
|
nbytes = DIM(buffer);
|
||||||
rc = gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes, &nbytes, a );
|
err = gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes, &nbytes, a );
|
||||||
if( !rc )
|
if (!err)
|
||||||
rc = iobuf_write( out, buffer, nbytes );
|
{
|
||||||
else if (gpg_err_code(rc) == GPG_ERR_TOO_SHORT )
|
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));
|
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. */
|
/* The buffer was too small. We better tell the user about
|
||||||
rc = gpg_error (GPG_ERR_TOO_LARGE);
|
* 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)
|
do_key (iobuf_t out, int ctb, PKT_public_key *pk)
|
||||||
{
|
{
|
||||||
gpg_error_t err = 0;
|
gpg_error_t err = 0;
|
||||||
/* The length of the body is stored in the packet's header, which
|
iobuf_t a;
|
||||||
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();
|
|
||||||
int i, nskey, npkey;
|
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
|
log_assert (ctb_pkttype (ctb) == PKT_PUBLIC_KEY
|
||||||
|| ctb_pkttype (ctb) == PKT_PUBLIC_SUBKEY
|
|| ctb_pkttype (ctb) == PKT_PUBLIC_SUBKEY
|
||||||
|| ctb_pkttype (ctb) == PKT_SECRET_KEY
|
|| ctb_pkttype (ctb) == PKT_SECRET_KEY
|
||||||
|| ctb_pkttype (ctb) == PKT_SECRET_SUBKEY);
|
|| ctb_pkttype (ctb) == PKT_SECRET_SUBKEY);
|
||||||
|
|
||||||
/* Write the version number - if none is specified, use 4 */
|
/* The length of the body is stored in the packet's header, which
|
||||||
if ( !pk->version )
|
* occurs before the body. Unfortunately, we don't know the length
|
||||||
iobuf_put ( a, 4 );
|
* of the packet's body until we've written all of the data! To
|
||||||
else
|
* work around this, we first write the data into this temporary
|
||||||
iobuf_put ( a, pk->version );
|
* buffer, then generate the header, and finally copy the content
|
||||||
write_32 (a, pk->timestamp );
|
* 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
|
/* Get number of secret and public parameters. They are held in one
|
||||||
array: the public ones followed by the secret ones. */
|
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)))
|
|| (pk->pubkey_algo == PUBKEY_ALGO_ECDH && (i == 0 || i == 2)))
|
||||||
err = gpg_mpi_write_nohdr (a, pk->pkey[i]);
|
err = gpg_mpi_write_nohdr (a, pk->pkey[i]);
|
||||||
else
|
else
|
||||||
err = gpg_mpi_write (a, pk->pkey[i]);
|
err = gpg_mpi_write (a, pk->pkey[i], NULL);
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Record the length of the public key part. */
|
||||||
|
pkbytes = iobuf_get_temp_length (a);
|
||||||
|
|
||||||
if (pk->seckey_info)
|
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. */
|
/* Build the header for protected (encrypted) secret parameters. */
|
||||||
if (ski->is_protected)
|
if (ski->is_protected)
|
||||||
{
|
{
|
||||||
/* OpenPGP protection according to rfc2440. */
|
iobuf_put (a, ski->sha1chk? 0xfe : 0xff); /* S2k usage. */
|
||||||
iobuf_put (a, ski->sha1chk? 0xfe : 0xff);
|
if (is_v5)
|
||||||
iobuf_put (a, ski->algo);
|
{
|
||||||
|
/* 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)
|
if (ski->s2k.mode >= 1000)
|
||||||
{
|
{
|
||||||
/* These modes are not possible in OpenPGP, we use them
|
/* 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. */
|
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)
|
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)
|
else if (ski->s2k.mode == 1002)
|
||||||
{
|
{
|
||||||
/* GnuPG extension - divert to OpenPGP smartcard. */
|
/* 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. */
|
/* Length of the serial number or 0 for no serial number. */
|
||||||
iobuf_put (a, ski->ivlen );
|
iobuf_put (a, ski->ivlen );
|
||||||
/* The serial number gets stored in the IV field. */
|
/* 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));
|
log_assert (gcry_mpi_get_flag (pk->pkey[npkey], GCRYMPI_FLAG_OPAQUE));
|
||||||
p = gcry_mpi_get_opaque (pk->pkey[npkey], &ndatabits);
|
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)
|
if (p)
|
||||||
iobuf_write (a, p, (ndatabits+7)/8 );
|
iobuf_write (a, p, (ndatabits+7)/8 );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Non-protected key. */
|
/* 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++ )
|
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;
|
goto leave;
|
||||||
|
|
||||||
write_16 (a, ski->csum );
|
write_16 (a, ski->csum );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -593,11 +662,23 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
|
|||||||
if (!err)
|
if (!err)
|
||||||
{
|
{
|
||||||
/* Build the header of the packet - which we must do after
|
/* Build the header of the packet - which we must do after
|
||||||
writing all the other stuff, so that we know the length of
|
* writing all the other stuff, so that we know the length of
|
||||||
the packet */
|
* the packet */
|
||||||
write_header2 (out, ctb, iobuf_get_temp_length(a), 0);
|
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. */
|
/* 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 */
|
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)
|
if (enc->pubkey_algo == PUBKEY_ALGO_ECDH && i == 1)
|
||||||
rc = gpg_mpi_write_nohdr (a, enc->data[i]);
|
rc = gpg_mpi_write_nohdr (a, enc->data[i]);
|
||||||
else
|
else
|
||||||
rc = gpg_mpi_write (a, enc->data[i]);
|
rc = gpg_mpi_write (a, enc->data[i], NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rc)
|
if (!rc)
|
||||||
@ -1135,10 +1216,10 @@ build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk)
|
|||||||
|
|
||||||
/* Write the new ISSUER_FPR subpacket. */
|
/* Write the new ISSUER_FPR subpacket. */
|
||||||
fingerprint_from_pk (pksk, buf+1, &fprlen);
|
fingerprint_from_pk (pksk, buf+1, &fprlen);
|
||||||
if (fprlen == 20)
|
if (fprlen == 20 || fprlen == 32)
|
||||||
{
|
{
|
||||||
buf[0] = pksk->version;
|
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. */
|
/* Write the timestamp. */
|
||||||
@ -1567,7 +1648,7 @@ do_signature( IOBUF out, int ctb, PKT_signature *sig )
|
|||||||
if ( !n )
|
if ( !n )
|
||||||
write_fake_data( a, sig->data[0] );
|
write_fake_data( a, sig->data[0] );
|
||||||
for (i=0; i < n && !rc ; i++ )
|
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)
|
if (!rc)
|
||||||
{
|
{
|
||||||
|
232
g10/keygen.c
232
g10/keygen.c
@ -1,6 +1,6 @@
|
|||||||
/* keygen.c - Generate a key pair
|
/* keygen.c - Generate a key pair
|
||||||
* Copyright (C) 1998-2007, 2009-2011 Free Software Foundation, Inc.
|
* 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.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
@ -59,6 +59,7 @@ const char *default_expiration_interval = "2y";
|
|||||||
/* Flag bits used during key generation. */
|
/* Flag bits used during key generation. */
|
||||||
#define KEYGEN_FLAG_NO_PROTECTION 1
|
#define KEYGEN_FLAG_NO_PROTECTION 1
|
||||||
#define KEYGEN_FLAG_TRANSIENT_KEY 2
|
#define KEYGEN_FLAG_TRANSIENT_KEY 2
|
||||||
|
#define KEYGEN_FLAG_CREATE_V5_KEY 4
|
||||||
|
|
||||||
/* Maximum number of supported algorithm preferences. */
|
/* Maximum number of supported algorithm preferences. */
|
||||||
#define MAX_PREFS 30
|
#define MAX_PREFS 30
|
||||||
@ -90,7 +91,9 @@ enum para_name {
|
|||||||
pHANDLE,
|
pHANDLE,
|
||||||
pKEYSERVER,
|
pKEYSERVER,
|
||||||
pKEYGRIP,
|
pKEYGRIP,
|
||||||
pSUBKEYGRIP
|
pSUBKEYGRIP,
|
||||||
|
pVERSION, /* Desired version of the key packet. */
|
||||||
|
pSUBVERSION, /* Ditto for the subpacket. */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct para_data_s {
|
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,
|
const char *expirestr,
|
||||||
int *r_algo, unsigned int *r_usage,
|
int *r_algo, unsigned int *r_usage,
|
||||||
u32 *r_expire, unsigned int *r_nbits,
|
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,
|
static void do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
|
||||||
struct output_control_s *outctrl, int card );
|
struct output_control_s *outctrl, int card );
|
||||||
static int write_keyblock (iobuf_t out, kbnode_t node);
|
static int write_keyblock (iobuf_t out, kbnode_t node);
|
||||||
static gpg_error_t gen_card_key (int keyno, int algo, int is_primary,
|
static gpg_error_t gen_card_key (int keyno, int algo, int is_primary,
|
||||||
kbnode_t pub_root, u32 *timestamp,
|
kbnode_t pub_root, u32 *timestamp,
|
||||||
u32 expireval);
|
u32 expireval, int keygen_flags);
|
||||||
static unsigned int get_keysize_range (int algo,
|
static unsigned int get_keysize_range (int algo,
|
||||||
unsigned int *min, unsigned int *max);
|
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
|
static void
|
||||||
add_keyserver_modify (PKT_signature *sig,int enabled)
|
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. */
|
/* Make sure that the MDC feature flag is set if needed. */
|
||||||
add_feature_mdc (sig,mdc_available);
|
add_feature_mdc (sig,mdc_available);
|
||||||
add_feature_aead (sig, aead_available);
|
add_feature_aead (sig, aead_available);
|
||||||
|
add_feature_v5 (sig, opt.flags.rfc4880bis);
|
||||||
add_keyserver_modify (sig,ks_modify);
|
add_keyserver_modify (sig,ks_modify);
|
||||||
keygen_add_keyserver_url(sig,NULL);
|
keygen_add_keyserver_url(sig,NULL);
|
||||||
|
|
||||||
@ -1370,7 +1416,7 @@ key_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp,
|
|||||||
static int
|
static int
|
||||||
do_create_from_keygrip (ctrl_t ctrl, int algo, const char *hexkeygrip,
|
do_create_from_keygrip (ctrl_t ctrl, int algo, const char *hexkeygrip,
|
||||||
kbnode_t pub_root, u32 timestamp, u32 expireval,
|
kbnode_t pub_root, u32 timestamp, u32 expireval,
|
||||||
int is_subkey)
|
int is_subkey, int keygen_flags)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
PACKET *pkt;
|
PACKET *pkt;
|
||||||
@ -1417,7 +1463,7 @@ do_create_from_keygrip (ctrl_t ctrl, int algo, const char *hexkeygrip,
|
|||||||
}
|
}
|
||||||
|
|
||||||
pk->timestamp = timestamp;
|
pk->timestamp = timestamp;
|
||||||
pk->version = 4;
|
pk->version = (keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4;
|
||||||
if (expireval)
|
if (expireval)
|
||||||
pk->expiredate = pk->timestamp + expireval;
|
pk->expiredate = pk->timestamp + expireval;
|
||||||
pk->pubkey_algo = algo;
|
pk->pubkey_algo = algo;
|
||||||
@ -1484,7 +1530,7 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
|
|||||||
}
|
}
|
||||||
|
|
||||||
pk->timestamp = timestamp;
|
pk->timestamp = timestamp;
|
||||||
pk->version = 4;
|
pk->version = (keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4;
|
||||||
if (expireval)
|
if (expireval)
|
||||||
pk->expiredate = pk->timestamp + expireval;
|
pk->expiredate = pk->timestamp + expireval;
|
||||||
pk->pubkey_algo = algo;
|
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
|
/* Basic key generation. Here we divert to the actual generation
|
||||||
routines based on the requested algorithm. */
|
routines based on the requested algorithm. */
|
||||||
static int
|
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,
|
u32 timestamp, u32 expiredate, int is_subkey,
|
||||||
int keygen_flags, const char *passphrase,
|
int keygen_flags, const char *passphrase,
|
||||||
char **cache_nonce_addr, char **passwd_nonce_addr)
|
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
|
* 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;
|
* 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
|
* 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
|
static gpg_error_t
|
||||||
parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
|
parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
|
||||||
int *r_algo, unsigned int *r_size,
|
int *r_algo, unsigned int *r_size,
|
||||||
unsigned int *r_keyuse,
|
unsigned int *r_keyuse,
|
||||||
char const **r_curve)
|
char const **r_curve, int *r_keyversion)
|
||||||
{
|
{
|
||||||
char *flags;
|
char *flags;
|
||||||
int algo;
|
int algo;
|
||||||
@ -3021,6 +3069,7 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
|
|||||||
int ecdh_or_ecdsa = 0;
|
int ecdh_or_ecdsa = 0;
|
||||||
unsigned int size;
|
unsigned int size;
|
||||||
int keyuse;
|
int keyuse;
|
||||||
|
int keyversion = 4;
|
||||||
int i;
|
int i;
|
||||||
const char *s;
|
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);
|
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
|
else
|
||||||
{
|
{
|
||||||
xfree (tokens);
|
xfree (tokens);
|
||||||
@ -3194,10 +3250,13 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
|
|||||||
*r_keyuse = keyuse;
|
*r_keyuse = keyuse;
|
||||||
if (r_curve)
|
if (r_curve)
|
||||||
*r_curve = curve;
|
*r_curve = curve;
|
||||||
|
if (r_keyversion)
|
||||||
|
*r_keyversion = keyversion;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Parse and return the standard key generation parameter.
|
/* Parse and return the standard key generation parameter.
|
||||||
* The string is expected to be in this format:
|
* 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.
|
* ecdsa := Use algorithm ECDSA.
|
||||||
* eddsa := Use algorithm EdDSA.
|
* eddsa := Use algorithm EdDSA.
|
||||||
* ecdh := Use algorithm ECDH.
|
* ecdh := Use algorithm ECDH.
|
||||||
|
* v5 := Create version 5 key (requires option --rfc4880bis)
|
||||||
*
|
*
|
||||||
* There are several defaults and fallbacks depending on the
|
* There are several defaults and fallbacks depending on the
|
||||||
* algorithm. PART can be used to select which part of STRING is
|
* 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,
|
int *r_algo, unsigned int *r_size,
|
||||||
unsigned int *r_keyuse,
|
unsigned int *r_keyuse,
|
||||||
char const **r_curve,
|
char const **r_curve,
|
||||||
|
int *r_version,
|
||||||
int *r_subalgo, unsigned int *r_subsize,
|
int *r_subalgo, unsigned int *r_subsize,
|
||||||
unsigned *r_subkeyuse,
|
unsigned int *r_subkeyuse,
|
||||||
char const **r_subcurve)
|
char const **r_subcurve,
|
||||||
|
int *r_subversion)
|
||||||
{
|
{
|
||||||
gpg_error_t err = 0;
|
gpg_error_t err = 0;
|
||||||
char *primary, *secondary;
|
char *primary, *secondary;
|
||||||
@ -3261,6 +3323,8 @@ parse_key_parameter_string (const char *string, int part,
|
|||||||
*r_keyuse = 0;
|
*r_keyuse = 0;
|
||||||
if (r_curve)
|
if (r_curve)
|
||||||
*r_curve = NULL;
|
*r_curve = NULL;
|
||||||
|
if (r_version)
|
||||||
|
*r_version = 4;
|
||||||
if (r_subalgo)
|
if (r_subalgo)
|
||||||
*r_subalgo = 0;
|
*r_subalgo = 0;
|
||||||
if (r_subsize)
|
if (r_subsize)
|
||||||
@ -3269,6 +3333,8 @@ parse_key_parameter_string (const char *string, int part,
|
|||||||
*r_subkeyuse = 0;
|
*r_subkeyuse = 0;
|
||||||
if (r_subcurve)
|
if (r_subcurve)
|
||||||
*r_subcurve = NULL;
|
*r_subcurve = NULL;
|
||||||
|
if (r_subversion)
|
||||||
|
*r_subversion = 4;
|
||||||
|
|
||||||
if (!string || !*string
|
if (!string || !*string
|
||||||
|| !ascii_strcasecmp (string, "default") || !strcmp (string, "-"))
|
|| !ascii_strcasecmp (string, "default") || !strcmp (string, "-"))
|
||||||
@ -3283,11 +3349,11 @@ parse_key_parameter_string (const char *string, int part,
|
|||||||
*secondary++ = 0;
|
*secondary++ = 0;
|
||||||
if (part == -1 || part == 0)
|
if (part == -1 || part == 0)
|
||||||
{
|
{
|
||||||
err = parse_key_parameter_part (primary, 0, 0, r_algo, r_size,
|
err = parse_key_parameter_part (primary, 0, 0, r_algo, r_size,
|
||||||
r_keyuse, r_curve);
|
r_keyuse, r_curve, r_version);
|
||||||
if (!err && part == -1)
|
if (!err && part == -1)
|
||||||
err = parse_key_parameter_part (secondary, 1, 0, r_subalgo, r_subsize,
|
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)
|
else if (part == 1)
|
||||||
{
|
{
|
||||||
@ -3300,14 +3366,17 @@ parse_key_parameter_string (const char *string, int part,
|
|||||||
if (secondary)
|
if (secondary)
|
||||||
{
|
{
|
||||||
err = parse_key_parameter_part (secondary, 1, 0,
|
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))
|
if (!err && suggested_use && r_keyuse && !(suggested_use & *r_keyuse))
|
||||||
err = parse_key_parameter_part (primary, 1, 1 /*(clear cert)*/,
|
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
|
else
|
||||||
err = parse_key_parameter_part (primary, 1, 0,
|
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);
|
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
|
* compatibility with the batch key generation. It would be
|
||||||
* better to make full use of parse_key_parameter_string. */
|
* better to make full use of parse_key_parameter_string. */
|
||||||
parse_key_parameter_string (NULL, 0, 0,
|
parse_key_parameter_string (NULL, 0, 0,
|
||||||
&i, NULL, NULL, NULL,
|
&i, NULL, NULL, NULL, NULL,
|
||||||
NULL, NULL, NULL, NULL);
|
NULL, NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
if (r_default)
|
if (r_default)
|
||||||
*r_default = 1;
|
*r_default = 1;
|
||||||
}
|
}
|
||||||
@ -3810,6 +3878,8 @@ read_parameter_file (ctrl_t ctrl, const char *fname )
|
|||||||
{ "Keygrip", pKEYGRIP },
|
{ "Keygrip", pKEYGRIP },
|
||||||
{ "Key-Grip", pKEYGRIP },
|
{ "Key-Grip", pKEYGRIP },
|
||||||
{ "Subkey-grip", pSUBKEYGRIP },
|
{ "Subkey-grip", pSUBKEYGRIP },
|
||||||
|
{ "Key-Version", pVERSION },
|
||||||
|
{ "Subkey-Version", pSUBVERSION },
|
||||||
{ NULL, 0 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
IOBUF fp;
|
IOBUF fp;
|
||||||
@ -3954,12 +4024,19 @@ read_parameter_file (ctrl_t ctrl, const char *fname )
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
r = xmalloc_clear( sizeof *r + strlen( value ) );
|
|
||||||
r->lnr = lnr;
|
if (!opt.flags.rfc4880bis && (keywords[i].key == pVERSION
|
||||||
r->key = keywords[i].key;
|
|| keywords[i].key == pSUBVERSION))
|
||||||
strcpy( r->u.value, value );
|
; /* Ignore version unless --rfc4880bis is active. */
|
||||||
r->next = para;
|
else
|
||||||
para = r;
|
{
|
||||||
|
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 )
|
if( err )
|
||||||
log_error("%s:%d: %s\n", fname, lnr, 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. */
|
/* Helper for quick_generate_keypair. */
|
||||||
static struct para_data_s *
|
static struct para_data_s *
|
||||||
quickgen_set_para (struct para_data_s *para, int for_subkey,
|
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;
|
struct para_data_s *r;
|
||||||
|
|
||||||
@ -4033,6 +4111,15 @@ quickgen_set_para (struct para_data_s *para, int for_subkey,
|
|||||||
para = r;
|
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;
|
return para;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4125,25 +4212,26 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
|
|||||||
|| !strcmp (usagestr, "-")))
|
|| !strcmp (usagestr, "-")))
|
||||||
{
|
{
|
||||||
/* Use default key parameters. */
|
/* Use default key parameters. */
|
||||||
int algo, subalgo;
|
int algo, subalgo, version, subversion;
|
||||||
unsigned int size, subsize;
|
unsigned int size, subsize;
|
||||||
unsigned int keyuse, subkeyuse;
|
unsigned int keyuse, subkeyuse;
|
||||||
const char *curve, *subcurve;
|
const char *curve, *subcurve;
|
||||||
|
|
||||||
err = parse_key_parameter_string (algostr, -1, 0,
|
err = parse_key_parameter_string (algostr, -1, 0,
|
||||||
&algo, &size, &keyuse, &curve,
|
&algo, &size, &keyuse, &curve, &version,
|
||||||
&subalgo, &subsize, &subkeyuse,
|
&subalgo, &subsize, &subkeyuse,
|
||||||
&subcurve);
|
&subcurve, &subversion);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
log_error (_("Key generation failed: %s\n"), gpg_strerror (err));
|
log_error (_("Key generation failed: %s\n"), gpg_strerror (err));
|
||||||
goto leave;
|
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)
|
if (subalgo)
|
||||||
para = quickgen_set_para (para, 1,
|
para = quickgen_set_para (para, 1,
|
||||||
subalgo, subsize, subcurve, subkeyuse);
|
subalgo, subsize, subcurve, subkeyuse,
|
||||||
|
subversion);
|
||||||
|
|
||||||
if (*expirestr)
|
if (*expirestr)
|
||||||
{
|
{
|
||||||
@ -4166,21 +4254,22 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Extended unattended mode. Creates only the primary key. */
|
/* Extended unattended mode. Creates only the primary key. */
|
||||||
int algo;
|
int algo, version;
|
||||||
unsigned int use;
|
unsigned int use;
|
||||||
u32 expire;
|
u32 expire;
|
||||||
unsigned int nbits;
|
unsigned int nbits;
|
||||||
const char *curve;
|
const char *curve;
|
||||||
|
|
||||||
err = parse_algo_usage_expire (ctrl, 0, algostr, usagestr, expirestr,
|
err = parse_algo_usage_expire (ctrl, 0, algostr, usagestr, expirestr,
|
||||||
&algo, &use, &expire, &nbits, &curve);
|
&algo, &use, &expire, &nbits, &curve,
|
||||||
|
&version);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
log_error (_("Key generation failed: %s\n"), gpg_strerror (err) );
|
log_error (_("Key generation failed: %s\n"), gpg_strerror (err) );
|
||||||
goto leave;
|
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 = xmalloc_clear (sizeof *r + 20);
|
||||||
r->key = pKEYEXPIRE;
|
r->key = pKEYEXPIRE;
|
||||||
r->u.expire = expire;
|
r->u.expire = expire;
|
||||||
@ -4494,7 +4583,7 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
|
|||||||
}
|
}
|
||||||
else /* Default key generation. */
|
else /* Default key generation. */
|
||||||
{
|
{
|
||||||
int subalgo;
|
int subalgo, version, subversion;
|
||||||
unsigned int size, subsize;
|
unsigned int size, subsize;
|
||||||
unsigned int keyuse, subkeyuse;
|
unsigned int keyuse, subkeyuse;
|
||||||
const char *curve, *subcurve;
|
const char *curve, *subcurve;
|
||||||
@ -4509,18 +4598,19 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
|
|||||||
, "--full-generate-key" );
|
, "--full-generate-key" );
|
||||||
|
|
||||||
err = parse_key_parameter_string (NULL, -1, 0,
|
err = parse_key_parameter_string (NULL, -1, 0,
|
||||||
&algo, &size, &keyuse, &curve,
|
&algo, &size, &keyuse, &curve, &version,
|
||||||
&subalgo, &subsize,
|
&subalgo, &subsize,
|
||||||
&subkeyuse, &subcurve);
|
&subkeyuse, &subcurve, &subversion);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
log_error (_("Key generation failed: %s\n"), gpg_strerror (err));
|
log_error (_("Key generation failed: %s\n"), gpg_strerror (err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
para = quickgen_set_para (para, 0, algo, size, curve, keyuse);
|
para = quickgen_set_para (para, 0, algo, size, curve, keyuse, version);
|
||||||
if (subalgo)
|
if (subalgo)
|
||||||
para = quickgen_set_para (para, 1,
|
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;
|
int algo;
|
||||||
u32 expire;
|
u32 expire;
|
||||||
const char *key_from_hexgrip = NULL;
|
const char *key_from_hexgrip = NULL;
|
||||||
|
unsigned int keygen_flags;
|
||||||
|
|
||||||
if (outctrl->dryrun)
|
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 );
|
algo = get_parameter_algo( para, pKEYTYPE, NULL );
|
||||||
expire = get_parameter_u32( para, pKEYEXPIRE );
|
expire = get_parameter_u32( para, pKEYEXPIRE );
|
||||||
key_from_hexgrip = get_parameter_value (para, pKEYGRIP);
|
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)
|
if (key_from_hexgrip)
|
||||||
err = do_create_from_keygrip (ctrl, algo, 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)
|
else if (!card)
|
||||||
err = do_create (algo,
|
err = do_create (algo,
|
||||||
get_parameter_uint( para, pKEYLENGTH ),
|
get_parameter_uint( para, pKEYLENGTH ),
|
||||||
@ -4818,13 +4914,13 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
|
|||||||
pub_root,
|
pub_root,
|
||||||
timestamp,
|
timestamp,
|
||||||
expire, 0,
|
expire, 0,
|
||||||
outctrl->keygen_flags,
|
keygen_flags,
|
||||||
get_parameter_passphrase (para),
|
get_parameter_passphrase (para),
|
||||||
&cache_nonce, NULL);
|
&cache_nonce, NULL);
|
||||||
else
|
else
|
||||||
err = gen_card_key (1, algo,
|
err = gen_card_key (1, algo,
|
||||||
1, pub_root, ×tamp,
|
1, pub_root, ×tamp,
|
||||||
expire);
|
expire, keygen_flags);
|
||||||
|
|
||||||
/* Get the pointer to the generated public key packet. */
|
/* Get the pointer to the generated public key packet. */
|
||||||
if (!err)
|
if (!err)
|
||||||
@ -4863,7 +4959,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
|
|||||||
if (!err && card && get_parameter (para, pAUTHKEYTYPE))
|
if (!err && card && get_parameter (para, pAUTHKEYTYPE))
|
||||||
{
|
{
|
||||||
err = gen_card_key (3, get_parameter_algo( para, pAUTHKEYTYPE, NULL ),
|
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)
|
if (!err)
|
||||||
err = write_keybinding (ctrl, pub_root, pri_psk, NULL,
|
err = write_keybinding (ctrl, pub_root, pri_psk, NULL,
|
||||||
PUBKEY_USAGE_AUTH, timestamp, cache_nonce);
|
PUBKEY_USAGE_AUTH, timestamp, cache_nonce);
|
||||||
@ -4875,11 +4971,16 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
|
|||||||
|
|
||||||
s = NULL;
|
s = NULL;
|
||||||
key_from_hexgrip = get_parameter_value (para, pSUBKEYGRIP);
|
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)
|
if (key_from_hexgrip)
|
||||||
err = do_create_from_keygrip (ctrl, subkey_algo, key_from_hexgrip,
|
err = do_create_from_keygrip (ctrl, subkey_algo, key_from_hexgrip,
|
||||||
pub_root, timestamp,
|
pub_root, timestamp,
|
||||||
get_parameter_u32 (para, pSUBKEYEXPIRE),
|
get_parameter_u32 (para, pSUBKEYEXPIRE),
|
||||||
1);
|
1, keygen_flags);
|
||||||
else if (!card || (s = get_parameter_value (para, pCARDBACKUPKEY)))
|
else if (!card || (s = get_parameter_value (para, pCARDBACKUPKEY)))
|
||||||
{
|
{
|
||||||
err = do_create (subkey_algo,
|
err = do_create (subkey_algo,
|
||||||
@ -4888,7 +4989,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
|
|||||||
pub_root,
|
pub_root,
|
||||||
timestamp,
|
timestamp,
|
||||||
get_parameter_u32 (para, pSUBKEYEXPIRE), 1,
|
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),
|
get_parameter_passphrase (para),
|
||||||
&cache_nonce, NULL);
|
&cache_nonce, NULL);
|
||||||
/* Get the pointer to the generated public subkey packet. */
|
/* 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
|
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)
|
if (!err)
|
||||||
@ -5032,13 +5134,15 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
|
|||||||
const char *algostr, const char *usagestr,
|
const char *algostr, const char *usagestr,
|
||||||
const char *expirestr,
|
const char *expirestr,
|
||||||
int *r_algo, unsigned int *r_usage, u32 *r_expire,
|
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;
|
gpg_error_t err;
|
||||||
int algo;
|
int algo;
|
||||||
unsigned int use, nbits;
|
unsigned int use, nbits;
|
||||||
u32 expire;
|
u32 expire;
|
||||||
int wantuse;
|
int wantuse;
|
||||||
|
int version = 4;
|
||||||
const char *curve = NULL;
|
const char *curve = NULL;
|
||||||
|
|
||||||
*r_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,
|
err = parse_key_parameter_string (algostr, for_subkey? 1 : 0,
|
||||||
usagestr? parse_usagestr (usagestr):0,
|
usagestr? parse_usagestr (usagestr):0,
|
||||||
&algo, &nbits, &use, &curve,
|
&algo, &nbits, &use, &curve, &version,
|
||||||
NULL, NULL, NULL, NULL);
|
NULL, NULL, NULL, NULL, NULL);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@ -5095,6 +5199,7 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
|
|||||||
*r_usage = use;
|
*r_usage = use;
|
||||||
*r_expire = expire;
|
*r_expire = expire;
|
||||||
*r_nbits = nbits;
|
*r_nbits = nbits;
|
||||||
|
*r_version = version;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5122,6 +5227,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
|
|||||||
char *serialno = NULL;
|
char *serialno = NULL;
|
||||||
char *cache_nonce = NULL;
|
char *cache_nonce = NULL;
|
||||||
char *passwd_nonce = NULL;
|
char *passwd_nonce = NULL;
|
||||||
|
int keygen_flags = 0;
|
||||||
|
|
||||||
interactive = (!algostr || !usagestr || !expirestr);
|
interactive = (!algostr || !usagestr || !expirestr);
|
||||||
|
|
||||||
@ -5203,10 +5309,16 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
|
|||||||
}
|
}
|
||||||
else /* Unattended mode. */
|
else /* Unattended mode. */
|
||||||
{
|
{
|
||||||
|
int version;
|
||||||
|
|
||||||
err = parse_algo_usage_expire (ctrl, 1, algostr, usagestr, expirestr,
|
err = parse_algo_usage_expire (ctrl, 1, algostr, usagestr, expirestr,
|
||||||
&algo, &use, &expire, &nbits, &curve);
|
&algo, &use, &expire, &nbits, &curve,
|
||||||
|
&version);
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
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
|
/* 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)
|
if (key_from_hexgrip)
|
||||||
{
|
{
|
||||||
err = do_create_from_keygrip (ctrl, algo, 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
|
else
|
||||||
{
|
{
|
||||||
@ -5245,7 +5358,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
|
|||||||
passwd = NULL;
|
passwd = NULL;
|
||||||
|
|
||||||
err = do_create (algo, nbits, curve,
|
err = do_create (algo, nbits, curve,
|
||||||
keyblock, cur_time, expire, 1, 0,
|
keyblock, cur_time, expire, 1, keygen_flags,
|
||||||
passwd, &cache_nonce, &passwd_nonce);
|
passwd, &cache_nonce, &passwd_nonce);
|
||||||
}
|
}
|
||||||
if (err)
|
if (err)
|
||||||
@ -5293,6 +5406,7 @@ generate_card_subkeypair (ctrl_t ctrl, kbnode_t pub_keyblock,
|
|||||||
PKT_public_key *sub_pk = NULL;
|
PKT_public_key *sub_pk = NULL;
|
||||||
int algo;
|
int algo;
|
||||||
struct agent_card_info_s info;
|
struct agent_card_info_s info;
|
||||||
|
int keygen_flags = 0; /* FIXME!!! */
|
||||||
|
|
||||||
log_assert (keyno >= 1 && keyno <= 3);
|
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
|
/* Note, that depending on the backend, the card key generation may
|
||||||
update CUR_TIME. */
|
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. */
|
/* Get the pointer to the generated public subkey packet. */
|
||||||
if (!err)
|
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
|
static gpg_error_t
|
||||||
gen_card_key (int keyno, int algo, int is_primary, kbnode_t pub_root,
|
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
|
#ifdef ENABLE_CARD_SUPPORT
|
||||||
gpg_error_t err;
|
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->timestamp = *timestamp;
|
||||||
pk->version = 4;
|
pk->version = (keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4;
|
||||||
if (expireval)
|
if (expireval)
|
||||||
pk->expiredate = pk->timestamp + expireval;
|
pk->expiredate = pk->timestamp + expireval;
|
||||||
pk->pubkey_algo = algo;
|
pk->pubkey_algo = algo;
|
||||||
|
100
g10/keyid.c
100
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
|
/* Hash a public key. This function is useful for v4 and v5
|
||||||
for v3 or v4 key signing. */
|
* fingerprints and for v3 or v4 key signing. */
|
||||||
void
|
void
|
||||||
hash_public_key (gcry_md_hd_t md, PKT_public_key *pk)
|
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];
|
unsigned int nn[PUBKEY_MAX_NPKEY];
|
||||||
byte *pp[PUBKEY_MAX_NPKEY];
|
byte *pp[PUBKEY_MAX_NPKEY];
|
||||||
int i;
|
int i;
|
||||||
unsigned int nbits;
|
unsigned int nbits;
|
||||||
size_t nbytes;
|
size_t nbytes;
|
||||||
int npkey = pubkey_get_npkey (pk->pubkey_algo);
|
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
|
/* FIXME: We can avoid the extra malloc by calling only the first
|
||||||
mpi_print here which computes the required length and calling the
|
mpi_print here which computes the required length and calling the
|
||||||
real mpi_print only at the end. The speed advantage would only be
|
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 */
|
if (is_v5)
|
||||||
/* What does it mean if n is greater than 0xFFFF ? */
|
{
|
||||||
gcry_md_putc ( md, n >> 8 ); /* 2 byte length header */
|
gcry_md_putc ( md, 0x9a ); /* ctb */
|
||||||
gcry_md_putc ( md, n );
|
gcry_md_putc ( md, n >> 24 ); /* 4 byte length header */
|
||||||
gcry_md_putc ( md, pk->version );
|
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 >> 24 );
|
||||||
gcry_md_putc ( md, pk->timestamp >> 16 );
|
gcry_md_putc ( md, pk->timestamp >> 16 );
|
||||||
gcry_md_putc ( md, pk->timestamp >> 8 );
|
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 );
|
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]
|
if(npkey==0 && pk->pkey[0]
|
||||||
&& gcry_mpi_get_flag (pk->pkey[0], GCRYMPI_FLAG_OPAQUE))
|
&& 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;
|
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 ();
|
BUG ();
|
||||||
hash_public_key(md,pk);
|
hash_public_key (md,pk);
|
||||||
gcry_md_final( md );
|
gcry_md_final (md);
|
||||||
|
|
||||||
return 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
|
* Get the keyid from the public key PK and store it at KEYID unless
|
||||||
* if this is not NULL. Return the 32 low bits of the keyid.
|
* this is NULL. Returns the 32 bit short keyid.
|
||||||
*/
|
*/
|
||||||
u32
|
u32
|
||||||
keyid_from_pk (PKT_public_key *pk, u32 *keyid)
|
keyid_from_pk (PKT_public_key *pk, u32 *keyid)
|
||||||
{
|
{
|
||||||
u32 lowbits;
|
|
||||||
u32 dummy_keyid[2];
|
u32 dummy_keyid[2];
|
||||||
|
|
||||||
if (!keyid)
|
if (!keyid)
|
||||||
@ -533,7 +553,6 @@ keyid_from_pk (PKT_public_key *pk, u32 *keyid)
|
|||||||
{
|
{
|
||||||
keyid[0] = pk->keyid[0];
|
keyid[0] = pk->keyid[0];
|
||||||
keyid[1] = pk->keyid[1];
|
keyid[1] = pk->keyid[1];
|
||||||
lowbits = keyid[1];
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -544,18 +563,25 @@ keyid_from_pk (PKT_public_key *pk, u32 *keyid)
|
|||||||
if(md)
|
if(md)
|
||||||
{
|
{
|
||||||
dp = gcry_md_read ( md, 0 );
|
dp = gcry_md_read ( md, 0 );
|
||||||
keyid[0] = buf32_to_u32 (dp+12);
|
if (pk->version == 5)
|
||||||
keyid[1] = buf32_to_u32 (dp+16);
|
{
|
||||||
lowbits = keyid[1];
|
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);
|
gcry_md_close (md);
|
||||||
pk->keyid[0] = keyid[0];
|
pk->keyid[0] = keyid[0];
|
||||||
pk->keyid[1] = keyid[1];
|
pk->keyid[1] = keyid[1];
|
||||||
}
|
}
|
||||||
else
|
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
|
else
|
||||||
{
|
{
|
||||||
const byte *dp = fprint;
|
const byte *dp = fprint;
|
||||||
keyid[0] = buf32_to_u32 (dp+12);
|
if (fprint_len == 20) /* v4 key */
|
||||||
keyid[1] = buf32_to_u32 (dp+16);
|
{
|
||||||
|
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];
|
return keyid[1];
|
||||||
@ -610,7 +644,7 @@ keyid_from_sig (PKT_signature *sig, u32 *keyid)
|
|||||||
keyid[0] = sig->keyid[0];
|
keyid[0] = sig->keyid[0];
|
||||||
keyid[1] = sig->keyid[1];
|
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;
|
size_t len;
|
||||||
gcry_md_hd_t md;
|
gcry_md_hd_t md;
|
||||||
|
|
||||||
md = do_fingerprint_md(pk);
|
md = do_fingerprint_md (pk);
|
||||||
dp = gcry_md_read( md, 0 );
|
dp = gcry_md_read (md, 0);
|
||||||
len = gcry_md_get_algo_dlen (gcry_md_get_algo (md));
|
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)
|
if (!array)
|
||||||
array = xmalloc ( len );
|
array = xmalloc ( len );
|
||||||
memcpy (array, dp, len );
|
memcpy (array, dp, len );
|
||||||
pk->keyid[0] = buf32_to_u32 (dp+12);
|
if (pk->version == 5)
|
||||||
pk->keyid[1] = buf32_to_u32 (dp+16);
|
{
|
||||||
|
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);
|
gcry_md_close( md);
|
||||||
|
|
||||||
if (ret_len)
|
if (ret_len)
|
||||||
|
@ -829,6 +829,8 @@ proc_plaintext( CTX c, PACKET *pkt )
|
|||||||
PKT_plaintext *pt = pkt->pkt.plaintext;
|
PKT_plaintext *pt = pkt->pkt.plaintext;
|
||||||
int any, clearsig, rc;
|
int any, clearsig, rc;
|
||||||
kbnode_t n;
|
kbnode_t n;
|
||||||
|
unsigned char *extrahash;
|
||||||
|
size_t extrahashlen;
|
||||||
|
|
||||||
/* This is a literal data packet. Bump a counter for later checks. */
|
/* This is a literal data packet. Bump a counter for later checks. */
|
||||||
literals_seen++;
|
literals_seen++;
|
||||||
@ -948,8 +950,33 @@ proc_plaintext( CTX c, PACKET *pkt )
|
|||||||
c->last_was_session_key = 0;
|
c->last_was_session_key = 0;
|
||||||
|
|
||||||
/* We add a marker control packet instead of the plaintext packet.
|
/* We add a marker control packet instead of the plaintext packet.
|
||||||
* This is so that we can later detect invalid packet sequences. */
|
* This is so that we can later detect invalid packet sequences.
|
||||||
n = new_kbnode (create_gpg_control (CTRLPKT_PLAINTEXT_MARK, NULL, 0));
|
* 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)
|
if (c->list)
|
||||||
add_kbnode (c->list, n);
|
add_kbnode (c->list, n);
|
||||||
else
|
else
|
||||||
@ -1019,7 +1046,8 @@ proc_compressed (CTX c, PACKET *pkt)
|
|||||||
* found. Returns: 0 = valid signature or an error code
|
* found. Returns: 0 = valid signature or an error code
|
||||||
*/
|
*/
|
||||||
static int
|
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)
|
int *is_expkey, int *is_revkey, PKT_public_key **r_pk)
|
||||||
{
|
{
|
||||||
PKT_signature *sig;
|
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
|
/* We only get here if we are checking the signature of a binary
|
||||||
(0x00) or text document (0x01). */
|
(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)
|
if (! rc)
|
||||||
md_good = md;
|
md_good = md;
|
||||||
else if (gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE && md2)
|
else if (gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE && md2)
|
||||||
{
|
{
|
||||||
PKT_public_key *pk2;
|
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);
|
r_pk? &pk2 : NULL);
|
||||||
if (!rc)
|
if (!rc)
|
||||||
{
|
{
|
||||||
@ -1275,7 +1305,7 @@ list_node (CTX c, kbnode_t node)
|
|||||||
if (opt.check_sigs)
|
if (opt.check_sigs)
|
||||||
{
|
{
|
||||||
fflush (stdout);
|
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))
|
switch (gpg_err_code (rc2))
|
||||||
{
|
{
|
||||||
case 0: sigrc = '!'; break;
|
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
|
* Returns NULL if not available. The returned buffer is valid as
|
||||||
* long as SIG is not modified. */
|
* long as SIG is not modified. */
|
||||||
const byte *
|
const byte *
|
||||||
@ -1748,7 +1778,7 @@ issuer_fpr_raw (PKT_signature *sig, size_t *r_len)
|
|||||||
size_t n;
|
size_t n;
|
||||||
|
|
||||||
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_ISSUER_FPR, &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;
|
*r_len = n - 1;
|
||||||
return p+1;
|
return p+1;
|
||||||
@ -1811,6 +1841,8 @@ check_sig_and_print (CTX c, kbnode_t node)
|
|||||||
char *issuer_fpr = NULL;
|
char *issuer_fpr = NULL;
|
||||||
PKT_public_key *pk = NULL; /* The public key for the signature or NULL. */
|
PKT_public_key *pk = NULL; /* The public key for the signature or NULL. */
|
||||||
int tried_ks_by_fpr;
|
int tried_ks_by_fpr;
|
||||||
|
const void *extrahash = NULL;
|
||||||
|
size_t extrahashlen = 0;
|
||||||
|
|
||||||
if (opt.skip_verify)
|
if (opt.skip_verify)
|
||||||
{
|
{
|
||||||
@ -1868,6 +1900,8 @@ check_sig_and_print (CTX c, kbnode_t node)
|
|||||||
{
|
{
|
||||||
if (n->next)
|
if (n->next)
|
||||||
goto ambiguous; /* We only allow one P packet. */
|
goto ambiguous; /* We only allow one P packet. */
|
||||||
|
extrahash = n->pkt->pkt.gpg_control->data;
|
||||||
|
extrahashlen = n->pkt->pkt.gpg_control->datalen;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
goto ambiguous;
|
goto ambiguous;
|
||||||
@ -1882,6 +1916,9 @@ check_sig_and_print (CTX c, kbnode_t node)
|
|||||||
&& (n->pkt->pkt.gpg_control->control
|
&& (n->pkt->pkt.gpg_control->control
|
||||||
== CTRLPKT_PLAINTEXT_MARK)))
|
== CTRLPKT_PLAINTEXT_MARK)))
|
||||||
goto ambiguous;
|
goto ambiguous;
|
||||||
|
extrahash = n->pkt->pkt.gpg_control->data;
|
||||||
|
extrahashlen = n->pkt->pkt.gpg_control->datalen;
|
||||||
|
|
||||||
for (n_sig=0, n = n->next;
|
for (n_sig=0, n = n->next;
|
||||||
n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next)
|
n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next)
|
||||||
n_sig++;
|
n_sig++;
|
||||||
@ -1912,6 +1949,8 @@ check_sig_and_print (CTX c, kbnode_t node)
|
|||||||
&& (n->pkt->pkt.gpg_control->control
|
&& (n->pkt->pkt.gpg_control->control
|
||||||
== CTRLPKT_PLAINTEXT_MARK)))
|
== CTRLPKT_PLAINTEXT_MARK)))
|
||||||
goto ambiguous;
|
goto ambiguous;
|
||||||
|
extrahash = n->pkt->pkt.gpg_control->data;
|
||||||
|
extrahashlen = n->pkt->pkt.gpg_control->datalen;
|
||||||
for (n_sig=0, n = n->next;
|
for (n_sig=0, n = n->next;
|
||||||
n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next)
|
n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next)
|
||||||
n_sig++;
|
n_sig++;
|
||||||
@ -1957,7 +1996,8 @@ check_sig_and_print (CTX c, kbnode_t node)
|
|||||||
if (sig->signers_uid)
|
if (sig->signers_uid)
|
||||||
log_info (_(" issuer \"%s\"\n"), 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 the key isn't found, check for a preferred keyserver. */
|
||||||
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && sig->flags.pref_ks)
|
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);
|
res = keyserver_import_keyid (c->ctrl, sig->keyid,spec, 1);
|
||||||
glo_ctrl.in_auto_key_retrieve--;
|
glo_ctrl.in_auto_key_retrieve--;
|
||||||
if (!res)
|
if (!res)
|
||||||
rc = do_check_sig (c, node, NULL,
|
rc = do_check_sig (c, node, extrahash, extrahashlen,
|
||||||
&is_expkey, &is_revkey, &pk);
|
NULL, &is_expkey, &is_revkey, &pk);
|
||||||
free_keyserver_spec (spec);
|
free_keyserver_spec (spec);
|
||||||
|
|
||||||
if (!rc)
|
if (!rc)
|
||||||
@ -2028,7 +2068,8 @@ check_sig_and_print (CTX c, kbnode_t node)
|
|||||||
glo_ctrl.in_auto_key_retrieve--;
|
glo_ctrl.in_auto_key_retrieve--;
|
||||||
free_keyserver_spec (spec);
|
free_keyserver_spec (spec);
|
||||||
if (!res)
|
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);
|
p = issuer_fpr_raw (sig, &n);
|
||||||
if (p)
|
if (p)
|
||||||
{
|
{
|
||||||
/* v4 packet with a SHA-1 fingerprint. */
|
/* v4 or v5 packet with a SHA-1/256 fingerprint. */
|
||||||
free_public_key (pk);
|
free_public_key (pk);
|
||||||
pk = NULL;
|
pk = NULL;
|
||||||
glo_ctrl.in_auto_key_retrieve++;
|
glo_ctrl.in_auto_key_retrieve++;
|
||||||
@ -2058,7 +2099,8 @@ check_sig_and_print (CTX c, kbnode_t node)
|
|||||||
tried_ks_by_fpr = 1;
|
tried_ks_by_fpr = 1;
|
||||||
glo_ctrl.in_auto_key_retrieve--;
|
glo_ctrl.in_auto_key_retrieve--;
|
||||||
if (!res)
|
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,
|
/* Fixme: If the fingerprint is embedded in the signature,
|
||||||
* compare it to the fingerprint of the returned key. */
|
* compare it to the fingerprint of the returned key. */
|
||||||
if (!res)
|
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
|
/* 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);
|
res = keyserver_import_keyid (c->ctrl, sig->keyid, opt.keyserver, 1);
|
||||||
glo_ctrl.in_auto_key_retrieve--;
|
glo_ctrl.in_auto_key_retrieve--;
|
||||||
if (!res)
|
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)
|
if (!rc || gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE)
|
||||||
|
@ -853,7 +853,7 @@ PACKET *create_gpg_control ( ctrlpkttype_t type,
|
|||||||
/*-- build-packet.c --*/
|
/*-- build-packet.c --*/
|
||||||
int build_packet (iobuf_t out, PACKET *pkt);
|
int build_packet (iobuf_t out, PACKET *pkt);
|
||||||
gpg_error_t build_packet_and_meta (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);
|
gpg_error_t gpg_mpi_write_nohdr (iobuf_t out, gcry_mpi_t a);
|
||||||
u32 calc_packet_length( PACKET *pkt );
|
u32 calc_packet_length( PACKET *pkt );
|
||||||
void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
|
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. */
|
* it and verifying the signature. */
|
||||||
gpg_error_t check_signature2 (ctrl_t ctrl,
|
gpg_error_t check_signature2 (ctrl_t ctrl,
|
||||||
PKT_signature *sig, gcry_md_hd_t digest,
|
PKT_signature *sig, gcry_md_hd_t digest,
|
||||||
|
const void *extrahash, size_t extrahashlen,
|
||||||
u32 *r_expiredate, int *r_expired, int *r_revoked,
|
u32 *r_expiredate, int *r_expired, int *r_revoked,
|
||||||
PKT_public_key **r_pk);
|
PKT_public_key **r_pk);
|
||||||
|
|
||||||
|
@ -1644,7 +1644,7 @@ parse_one_sig_subpkt (const byte * buffer, size_t n, int type)
|
|||||||
if (n < 8)
|
if (n < 8)
|
||||||
break;
|
break;
|
||||||
return 0;
|
return 0;
|
||||||
case SIGSUBPKT_ISSUER_FPR: /* issuer key ID */
|
case SIGSUBPKT_ISSUER_FPR: /* issuer key fingerprint */
|
||||||
if (n < 21)
|
if (n < 21)
|
||||||
break;
|
break;
|
||||||
return 0;
|
return 0;
|
||||||
@ -2078,10 +2078,23 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
|
|||||||
&& opt.verbose)
|
&& opt.verbose)
|
||||||
log_info ("signature packet without timestamp\n");
|
log_info ("signature packet without timestamp\n");
|
||||||
|
|
||||||
p = parse_sig_subpkt2 (sig, SIGSUBPKT_ISSUER);
|
/* Set the key id. We first try the issuer fingerprint and if
|
||||||
if (p)
|
* it is a v4 signature the fallback to the issuer. Note that
|
||||||
{
|
* only the issuer packet is also searched in the unhashed area. */
|
||||||
sig->keyid[0] = buf32_to_u32 (p);
|
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);
|
sig->keyid[1] = buf32_to_u32 (p + 4);
|
||||||
}
|
}
|
||||||
else if (!(sig->pubkey_algo >= 100 && sig->pubkey_algo <= 110)
|
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;
|
int npkey, nskey;
|
||||||
u32 keyid[2];
|
u32 keyid[2];
|
||||||
PKT_public_key *pk;
|
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;
|
(void) hdr;
|
||||||
|
|
||||||
@ -2318,12 +2334,13 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else if (version == 4)
|
else if (version == 4)
|
||||||
{
|
is_v5 = 0;
|
||||||
/* The only supported version. Use an older gpg
|
else if (version == 5)
|
||||||
version (i.e. gpg 1.4) to parse v3 packets. */
|
is_v5 = 1;
|
||||||
}
|
|
||||||
else if (version == 2 || version == 3)
|
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)
|
if (opt.verbose > 1)
|
||||||
log_info ("packet(%d) with obsolete version %d\n", pkttype, version);
|
log_info ("packet(%d) with obsolete version %d\n", pkttype, version);
|
||||||
if (list_mode)
|
if (list_mode)
|
||||||
@ -2341,7 +2358,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pktlen < 11)
|
if (pktlen < (is_v5? 15:11))
|
||||||
{
|
{
|
||||||
log_error ("packet(%d) too short\n", pkttype);
|
log_error ("packet(%d) too short\n", pkttype);
|
||||||
if (list_mode)
|
if (list_mode)
|
||||||
@ -2364,14 +2381,28 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
|
|||||||
max_expiredate = 0;
|
max_expiredate = 0;
|
||||||
algorithm = iobuf_get_noeof (inp);
|
algorithm = iobuf_get_noeof (inp);
|
||||||
pktlen--;
|
pktlen--;
|
||||||
|
if (is_v5)
|
||||||
|
{
|
||||||
|
pkbytes = read_32 (inp);
|
||||||
|
pktlen -= 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pkbytes = 0;
|
||||||
|
|
||||||
if (list_mode)
|
if (list_mode)
|
||||||
es_fprintf (listfp, ":%s key packet:\n"
|
{
|
||||||
"\tversion %d, algo %d, created %lu, expires %lu\n",
|
es_fprintf (listfp, ":%s key packet:\n"
|
||||||
pkttype == PKT_PUBLIC_KEY ? "public" :
|
"\tversion %d, algo %d, created %lu, expires %lu",
|
||||||
pkttype == PKT_SECRET_KEY ? "secret" :
|
pkttype == PKT_PUBLIC_KEY ? "public" :
|
||||||
pkttype == PKT_PUBLIC_SUBKEY ? "public sub" :
|
pkttype == PKT_SECRET_KEY ? "secret" :
|
||||||
pkttype == PKT_SECRET_SUBKEY ? "secret sub" : "??",
|
pkttype == PKT_PUBLIC_SUBKEY ? "public sub" :
|
||||||
version, algorithm, timestamp, expiredate);
|
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->timestamp = timestamp;
|
||||||
pk->expiredate = expiredate;
|
pk->expiredate = expiredate;
|
||||||
@ -2446,6 +2477,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
|
|||||||
struct seckey_info *ski;
|
struct seckey_info *ski;
|
||||||
byte temp[16];
|
byte temp[16];
|
||||||
size_t snlen = 0;
|
size_t snlen = 0;
|
||||||
|
unsigned int skbytes;
|
||||||
|
|
||||||
if (pktlen < 1)
|
if (pktlen < 1)
|
||||||
{
|
{
|
||||||
@ -2462,23 +2494,42 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
|
|||||||
|
|
||||||
ski->algo = iobuf_get_noeof (inp);
|
ski->algo = iobuf_get_noeof (inp);
|
||||||
pktlen--;
|
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)
|
if (ski->algo)
|
||||||
{
|
{
|
||||||
ski->is_protected = 1;
|
ski->is_protected = 1;
|
||||||
ski->s2k.count = 0;
|
ski->s2k.count = 0;
|
||||||
if (ski->algo == 254 || ski->algo == 255)
|
if (ski->algo == 254 || ski->algo == 255)
|
||||||
{
|
{
|
||||||
if (pktlen < 3)
|
if (pktlen < 3)
|
||||||
{
|
{
|
||||||
err = gpg_error (GPG_ERR_INV_PACKET);
|
err = gpg_error (GPG_ERR_INV_PACKET);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
ski->sha1chk = (ski->algo == 254);
|
|
||||||
|
ski->sha1chk = (ski->algo == 254);
|
||||||
ski->algo = iobuf_get_noeof (inp);
|
ski->algo = iobuf_get_noeof (inp);
|
||||||
pktlen--;
|
pktlen--;
|
||||||
/* Note that a ski->algo > 110 is illegal, but I'm not
|
/* Note that a ski->algo > 110 is illegal, but I'm not
|
||||||
erroring on it here as otherwise there would be no
|
* erroring out here as otherwise there would be no way
|
||||||
way to delete such a key. */
|
* to delete such a key. */
|
||||||
ski->s2k.mode = iobuf_get_noeof (inp);
|
ski->s2k.mode = iobuf_get_noeof (inp);
|
||||||
pktlen--;
|
pktlen--;
|
||||||
ski->s2k.hash_algo = iobuf_get_noeof (inp);
|
ski->s2k.hash_algo = iobuf_get_noeof (inp);
|
||||||
@ -2504,10 +2555,8 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Read the salt. */
|
/* 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--)
|
for (i = 0; i < 8 && pktlen; i++, pktlen--)
|
||||||
temp[i] = iobuf_get_noeof (inp);
|
temp[i] = iobuf_get_noeof (inp);
|
||||||
if (i < 8)
|
if (i < 8)
|
||||||
@ -2516,7 +2565,6 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
memcpy (ski->s2k.salt, temp, 8);
|
memcpy (ski->s2k.salt, temp, 8);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check the mode. */
|
/* Check the mode. */
|
||||||
@ -2616,7 +2664,9 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
|
|||||||
* ski->ivlen = cipher_get_blocksize (ski->algo);
|
* ski->ivlen = cipher_get_blocksize (ski->algo);
|
||||||
* won't work. The only solution I see is to hardwire it.
|
* won't work. The only solution I see is to hardwire it.
|
||||||
* NOTE: if you change the ivlen above 16, don't forget to
|
* 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);
|
ski->ivlen = openpgp_cipher_blocklen (ski->algo);
|
||||||
log_assert (ski->ivlen <= sizeof (temp));
|
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);
|
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.
|
/* It does not make sense to read it into secure memory.
|
||||||
* If the user is so careless, not to protect his secret key,
|
* If the user is so careless, not to protect his secret key,
|
||||||
* we can assume, that he operates an open system :=(.
|
* 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
|
/* Ugly: The length is encrypted too, so we read all stuff
|
||||||
* up to the end of the packet into the first SKEY
|
* 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,
|
pk->pkey[npkey] = gcry_mpi_set_opaque (NULL,
|
||||||
read_rest (inp, pktlen),
|
read_rest (inp, pktlen),
|
||||||
pktlen * 8);
|
pktlen * 8);
|
||||||
/* Mark that MPI as protected - we need this information for
|
/* Mark that MPI as protected - we need this information for
|
||||||
importing a key. The OPAQUE flag can't be used because
|
* importing a key. The OPAQUE flag can't be used because
|
||||||
we also store public EdDSA values in opaque MPIs. */
|
* we also store public EdDSA values in opaque MPIs. */
|
||||||
if (pk->pkey[npkey])
|
if (pk->pkey[npkey])
|
||||||
gcry_mpi_set_flag (pk->pkey[npkey], GCRYMPI_FLAG_USER1);
|
gcry_mpi_set_flag (pk->pkey[npkey], GCRYMPI_FLAG_USER1);
|
||||||
pktlen = 0;
|
pktlen = 0;
|
||||||
@ -3509,11 +3574,13 @@ create_gpg_control (ctrlpkttype_t type, const byte * data, size_t datalen)
|
|||||||
PACKET *packet;
|
PACKET *packet;
|
||||||
byte *p;
|
byte *p;
|
||||||
|
|
||||||
|
if (!data)
|
||||||
|
datalen = 0;
|
||||||
|
|
||||||
packet = xmalloc (sizeof *packet);
|
packet = xmalloc (sizeof *packet);
|
||||||
init_packet (packet);
|
init_packet (packet);
|
||||||
packet->pkttype = PKT_GPG_CONTROL;
|
packet->pkttype = PKT_GPG_CONTROL;
|
||||||
packet->pkt.gpg_control = xmalloc (sizeof *packet->pkt.gpg_control
|
packet->pkt.gpg_control = xmalloc (sizeof *packet->pkt.gpg_control + datalen);
|
||||||
+ datalen - 1);
|
|
||||||
packet->pkt.gpg_control->control = type;
|
packet->pkt.gpg_control->control = type;
|
||||||
packet->pkt.gpg_control->datalen = datalen;
|
packet->pkt.gpg_control->datalen = datalen;
|
||||||
p = packet->pkt.gpg_control->data;
|
p = packet->pkt.gpg_control->data;
|
||||||
|
@ -37,11 +37,14 @@
|
|||||||
|
|
||||||
static int check_signature_end (PKT_public_key *pk, PKT_signature *sig,
|
static int check_signature_end (PKT_public_key *pk, PKT_signature *sig,
|
||||||
gcry_md_hd_t digest,
|
gcry_md_hd_t digest,
|
||||||
|
const void *extrahash, size_t extrahashlen,
|
||||||
int *r_expired, int *r_revoked,
|
int *r_expired, int *r_revoked,
|
||||||
PKT_public_key *ret_pk);
|
PKT_public_key *ret_pk);
|
||||||
|
|
||||||
static int check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig,
|
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. */
|
/* Statistics for signature verification. */
|
||||||
@ -69,7 +72,7 @@ sig_check_dump_stats (void)
|
|||||||
int
|
int
|
||||||
check_signature (ctrl_t ctrl, PKT_signature *sig, gcry_md_hd_t digest)
|
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
|
* signature data from the version number through the hashed subpacket
|
||||||
* data (inclusive) is hashed.")
|
* 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
|
* If R_EXPIREDATE is not NULL, R_EXPIREDATE is set to the key's
|
||||||
* expiry.
|
* 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. */
|
* Returns 0 on success. An error code otherwise. */
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
check_signature2 (ctrl_t ctrl,
|
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 *r_expired, int *r_revoked, PKT_public_key **r_pk)
|
||||||
{
|
{
|
||||||
int rc=0;
|
int rc=0;
|
||||||
@ -179,7 +187,8 @@ check_signature2 (ctrl_t ctrl,
|
|||||||
if (r_expiredate)
|
if (r_expiredate)
|
||||||
*r_expiredate = pk->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
|
/* Check the backsig. This is a back signature (0x19) from
|
||||||
* the subkey on the primary key. The idea here is that it
|
* 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
|
static int
|
||||||
check_signature_end (PKT_public_key *pk, PKT_signature *sig,
|
check_signature_end (PKT_public_key *pk, PKT_signature *sig,
|
||||||
gcry_md_hd_t digest,
|
gcry_md_hd_t digest,
|
||||||
|
const void *extrahash, size_t extrahashlen,
|
||||||
int *r_expired, int *r_revoked, PKT_public_key *ret_pk)
|
int *r_expired, int *r_revoked, PKT_public_key *ret_pk)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
@ -432,7 +442,8 @@ check_signature_end (PKT_public_key *pk, PKT_signature *sig,
|
|||||||
r_expired, r_revoked)))
|
r_expired, r_revoked)))
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
if ((rc = check_signature_end_simple (pk, sig, digest)))
|
if ((rc = check_signature_end_simple (pk, sig, digest,
|
||||||
|
extrahash, extrahashlen)))
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
if (!rc && ret_pk)
|
if (!rc && ret_pk)
|
||||||
@ -447,7 +458,8 @@ check_signature_end (PKT_public_key *pk, PKT_signature *sig,
|
|||||||
* expiration, revocation, etc. */
|
* expiration, revocation, etc. */
|
||||||
static int
|
static int
|
||||||
check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig,
|
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;
|
gcry_mpi_t result = NULL;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
@ -539,8 +551,13 @@ check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig,
|
|||||||
/* - One octet content format
|
/* - One octet content format
|
||||||
* - File name (one octet length followed by the name)
|
* - File name (one octet length followed by the name)
|
||||||
* - Four octet timestamp */
|
* - Four octet timestamp */
|
||||||
memset (buf, 0, 6);
|
if (extrahash && extrahashlen)
|
||||||
gcry_md_write (digest, buf, 6);
|
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. */
|
/* Add some magic per Section 5.2.4 of RFC 4880. */
|
||||||
i = 0;
|
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,main_pk);
|
||||||
hash_public_key(md,sub_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);
|
cache_sig_result(backsig,rc);
|
||||||
gcry_md_close(md);
|
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);
|
log_assert (packet->pkttype == PKT_PUBLIC_KEY);
|
||||||
hash_public_key (md, packet->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))
|
else if (IS_BACK_SIG (sig))
|
||||||
{
|
{
|
||||||
log_assert (packet->pkttype == PKT_PUBLIC_KEY);
|
log_assert (packet->pkttype == PKT_PUBLIC_KEY);
|
||||||
hash_public_key (md, packet->pkt.public_key);
|
hash_public_key (md, packet->pkt.public_key);
|
||||||
hash_public_key (md, signer);
|
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))
|
else if (IS_SUBKEY_SIG (sig) || IS_SUBKEY_REV (sig))
|
||||||
{
|
{
|
||||||
log_assert (packet->pkttype == PKT_PUBLIC_SUBKEY);
|
log_assert (packet->pkttype == PKT_PUBLIC_SUBKEY);
|
||||||
hash_public_key (md, pripk);
|
hash_public_key (md, pripk);
|
||||||
hash_public_key (md, packet->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_UID_SIG (sig) || IS_UID_REV (sig))
|
else if (IS_UID_SIG (sig) || IS_UID_REV (sig))
|
||||||
{
|
{
|
||||||
log_assert (packet->pkttype == PKT_USER_ID);
|
log_assert (packet->pkttype == PKT_USER_ID);
|
||||||
hash_public_key (md, pripk);
|
hash_public_key (md, pripk);
|
||||||
hash_uid_packet (packet->pkt.user_id, md, sig);
|
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
|
else
|
||||||
{
|
{
|
||||||
|
12
g10/sign.c
12
g10/sign.c
@ -49,6 +49,10 @@
|
|||||||
#define LF "\n"
|
#define LF "\n"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Hack */
|
||||||
|
static int recipient_digest_algo;
|
||||||
|
|
||||||
|
|
||||||
/* A type for the extra data we hash into v5 signature packets. */
|
/* A type for the extra data we hash into v5 signature packets. */
|
||||||
struct pt_extra_hash_data_s
|
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;
|
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
|
* Create notations and other stuff. It is assumed that the strings in
|
||||||
* STRLIST are already checked to contain only printable data and have
|
* 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)->mode = pt->mode;
|
||||||
(*r_extrahash)->timestamp = pt->timestamp;
|
(*r_extrahash)->timestamp = pt->timestamp;
|
||||||
(*r_extrahash)->namelen = pt->namelen;
|
(*r_extrahash)->namelen = pt->namelen;
|
||||||
/* Note that the last byte or NAME won't be initialized
|
/* Note that the last byte of NAME won't be initialized
|
||||||
* becuase we don't need it. */
|
* because we don't need it. */
|
||||||
memcpy ((*r_extrahash)->name, pt->name, pt->namelen);
|
memcpy ((*r_extrahash)->name, pt->name, pt->namelen);
|
||||||
}
|
}
|
||||||
pt->buf = NULL;
|
pt->buf = NULL;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user