agent: Fix importing protected secret key.

* agent/cvt-openpgp.c (do_unprotect): Only modify SKEY when it is
correctly decrypted.

--

GnuPG-bug-id: 5122
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
This commit is contained in:
NIIBE Yutaka 2021-06-09 10:57:52 +09:00
parent c3a9ee0b65
commit 7a80004d54
1 changed files with 49 additions and 21 deletions

View File

@ -532,13 +532,14 @@ do_unprotect (const char *passphrase,
const unsigned char *p; const unsigned char *p;
unsigned char *data; unsigned char *data;
u16 csum_pgp7 = 0; u16 csum_pgp7 = 0;
gcry_mpi_t skey_encrypted = skey[npkey];
if (!gcry_mpi_get_flag (skey[npkey], GCRYMPI_FLAG_USER1)) if (!gcry_mpi_get_flag (skey_encrypted, GCRYMPI_FLAG_USER1))
{ {
gcry_cipher_close (cipher_hd); gcry_cipher_close (cipher_hd);
return gpg_error (GPG_ERR_BAD_SECKEY); return gpg_error (GPG_ERR_BAD_SECKEY);
} }
p = gcry_mpi_get_opaque (skey[npkey], &ndatabits); p = gcry_mpi_get_opaque (skey_encrypted, &ndatabits);
ndata = (ndatabits+7)/8; ndata = (ndatabits+7)/8;
if (ndata > 1) if (ndata > 1)
@ -600,33 +601,48 @@ do_unprotect (const char *passphrase,
because the length may have an arbitrary value. */ because the length may have an arbitrary value. */
if (desired_csum == actual_csum) if (desired_csum == actual_csum)
{ {
for (i=npkey; i < nskey; i++ ) for (i = npkey; i < nskey; i++)
{ {
if (scan_pgp_format (&tmpmpi, pubkey_algo, p, ndata, &nbytes)) if (scan_pgp_format (&tmpmpi, pubkey_algo, p, ndata, &nbytes))
{ break;
/* Checksum was okay, but not correctly decrypted. */
desired_csum = 0;
actual_csum = 1; /* Mark checksum bad. */
break;
}
gcry_mpi_release (skey[i]);
skey[i] = tmpmpi; skey[i] = tmpmpi;
ndata -= nbytes; ndata -= nbytes;
p += nbytes; p += nbytes;
} }
skey[i] = NULL;
skeylen = i;
log_assert (skeylen <= skeysize);
/* Note: at this point NDATA should be 2 for a simple if (i == nskey)
checksum or 20 for the sha1 digest. */ {
skey[nskey] = NULL;
skeylen = nskey;
gcry_mpi_release (skey_encrypted);
log_assert (skeylen <= skeysize);
/* Note: at this point NDATA should be 2 for a simple
checksum or 20 for the sha1 digest. */
}
else
{
/* Checksum was okay, but not correctly decrypted. */
desired_csum = 0;
actual_csum = 1; /* Mark checksum bad. */
/* Recover encrypted SKEY. */
for (--i; i >= npkey; i--)
{
gcry_mpi_release (skey[i]);
skey[i] = NULL;
}
skey[npkey] = skey_encrypted;
}
} }
xfree(data); xfree(data);
} }
else /* Packet version <= 3. */ else /* Packet version <= 3. */
{ {
unsigned char *buffer; unsigned char *buffer;
gcry_mpi_t skey_tmpmpi[10];
log_assert (nskey - npkey <= 10);
for (i = npkey; i < nskey; i++) for (i = npkey; i < nskey; i++)
{ {
const unsigned char *p; const unsigned char *p;
@ -663,14 +679,26 @@ do_unprotect (const char *passphrase,
err = scan_pgp_format (&tmpmpi, pubkey_algo, buffer, ndata, &nbytes); err = scan_pgp_format (&tmpmpi, pubkey_algo, buffer, ndata, &nbytes);
xfree (buffer); xfree (buffer);
if (err) if (err)
break;
skey_tmpmpi[i - npkey] = tmpmpi;
}
if (i == nskey)
{
for (i = npkey; i < nskey; i++)
{ {
/* Checksum was okay, but not correctly decrypted. */ gcry_mpi_release (skey[i]);
desired_csum = 0; skey[i] = skey_tmpmpi[i - npkey];
actual_csum = 1; /* Mark checksum bad. */
break;
} }
gcry_mpi_release (skey[i]); }
skey[i] = tmpmpi; else
{
/* Checksum was okay, but not correctly decrypted. */
desired_csum = 0;
actual_csum = 1; /* Mark checksum bad. */
for (--i; i >= npkey; i--)
gcry_mpi_release (skey_tmpmpi[i - npkey]);
} }
} }
gcry_cipher_close (cipher_hd); gcry_cipher_close (cipher_hd);