aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNIIBE Yutaka <[email protected]>2022-04-28 06:12:01 +0000
committerNIIBE Yutaka <[email protected]>2022-04-28 06:12:01 +0000
commit3fcef7371480cce392d690897d42955f1b19c12a (patch)
tree7a0e5280e01a48244fec94e79dfd32a7ee3fd2d2
parentRevert "gpg: Accept Ed25519 private key in SOS which reserves leading zeros." (diff)
downloadgnupg-3fcef7371480cce392d690897d42955f1b19c12a.tar.gz
gnupg-3fcef7371480cce392d690897d42955f1b19c12a.zip
gpg: Handle leading-zeros private key for Ed25519.
* g10/parse-packet.c (mpi_read_detect_0_removal): New. (parse_key): Use mpi_read_detect_0_removal for PUBKEY_ALGO_EDDSA to tweak the checksum. -- GnuPG-bug-id: 5120 Signed-off-by: NIIBE Yutaka <[email protected]>
-rw-r--r--g10/parse-packet.c95
1 files changed, 94 insertions, 1 deletions
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index 3021f76b4..aee6e0798 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -188,6 +188,92 @@ mpi_read (iobuf_t inp, unsigned int *ret_nread, int secure)
}
+/* Read an external representation (which is possibly an SOS) and
+ return the MPI. The external format is a 16-bit unsigned value
+ stored in network byte order giving information for the following
+ octets.
+
+ The caller must set *RET_NREAD to the maximum number of bytes to
+ read from the pipeline INP. This function sets *RET_NREAD to be
+ the number of bytes actually read from the pipeline.
+
+ If SECURE is true, the integer is stored in secure memory
+ (allocated using gcry_xmalloc_secure). */
+static gcry_mpi_t
+mpi_read_detect_0_removal (iobuf_t inp, unsigned int *ret_nread, int secure,
+ u16 *r_csum_tweak)
+{
+ int c, c1, c2, i;
+ unsigned int nmax = *ret_nread;
+ unsigned int nbits, nbits1, nbytes;
+ size_t nread = 0;
+ gcry_mpi_t a = NULL;
+ byte *buf = NULL;
+ byte *p;
+
+ if (!nmax)
+ goto overflow;
+
+ if ((c = c1 = iobuf_get (inp)) == -1)
+ goto leave;
+ if (++nread == nmax)
+ goto overflow;
+ nbits = c << 8;
+ if ((c = c2 = iobuf_get (inp)) == -1)
+ goto leave;
+ ++nread;
+ nbits |= c;
+ if (nbits > MAX_EXTERN_MPI_BITS)
+ {
+ log_error ("mpi too large (%u bits)\n", nbits);
+ goto leave;
+ }
+
+ nbytes = (nbits + 7) / 8;
+ buf = secure ? gcry_xmalloc_secure (nbytes + 2) : gcry_xmalloc (nbytes + 2);
+ p = buf;
+ p[0] = c1;
+ p[1] = c2;
+ for (i = 0; i < nbytes; i++)
+ {
+ if (nread == nmax)
+ goto overflow;
+
+ c = iobuf_get (inp);
+ if (c == -1)
+ goto leave;
+
+ p[i + 2] = c;
+
+ nread ++;
+ }
+
+ if (gcry_mpi_scan (&a, GCRYMPI_FMT_PGP, buf, nread, &nread))
+ a = NULL;
+
+ /* Possibly, it has leading zeros. */
+ nbits1 = gcry_mpi_get_nbits (a);
+ if (nbits > nbits1)
+ {
+ *r_csum_tweak -= (nbits >> 8);
+ *r_csum_tweak -= (nbits & 0xff);
+ *r_csum_tweak += (nbits1 >> 8);
+ *r_csum_tweak += (nbits1 & 0xff);
+ }
+
+ *ret_nread = nread;
+ gcry_free(buf);
+ return a;
+
+ overflow:
+ log_error ("mpi larger than indicated length (%u bits)\n", 8*nmax);
+ leave:
+ *ret_nread = nread;
+ gcry_free(buf);
+ return a;
+}
+
+
/* Register STRING as a known critical notation name. */
void
register_known_notation (const char *string)
@@ -2724,6 +2810,8 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
}
else
{
+ u16 csum_tweak = 0;
+
/* Not encrypted. */
for (i = npkey; i < nskey; i++)
{
@@ -2735,7 +2823,11 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
goto leave;
}
n = pktlen;
- pk->pkey[i] = mpi_read (inp, &n, 0);
+ if (algorithm == PUBKEY_ALGO_EDDSA)
+ pk->pkey[i] = mpi_read_detect_0_removal (inp, &n, 0,
+ &csum_tweak);
+ else
+ pk->pkey[i] = mpi_read (inp, &n, 0);
pktlen -= n;
if (list_mode)
{
@@ -2756,6 +2848,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
goto leave;
}
ski->csum = read_16 (inp);
+ ski->csum += csum_tweak;
pktlen -= 2;
if (list_mode)
es_fprintf (listfp, "\tchecksum: %04hx\n", ski->csum);