aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNIIBE Yutaka <[email protected]>2021-12-22 11:11:42 +0000
committerNIIBE Yutaka <[email protected]>2021-12-22 11:11:42 +0000
commitd08072093928f187aa3dde579b9be5eb87710eeb (patch)
tree1e6fd60796e448af716408f92ee15bb1038c7bd4
parentexperiment: Fix for signature R+S in OpenPGP R part. (diff)
downloadgnupg-gniibe/v5/448.tar.gz
gnupg-gniibe/v5/448.zip
experiment: Handle S=0 in EdDSA by SOS("0").gniibe/v5/448
Signed-off-by: NIIBE Yutaka <[email protected]>
-rw-r--r--g10/parse-packet.c34
-rw-r--r--g10/pkglue.c14
2 files changed, 33 insertions, 15 deletions
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index 7c54a1ca8..3f3920dac 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -188,6 +188,22 @@ mpi_read (iobuf_t inp, unsigned int *ret_nread, int secure)
}
+/* Return an object for SOS which represents MPI(0). */
+static gcry_mpi_t
+sos_zero (void)
+{
+ /*
+ * We don't do gcry_mpi_set_opaque (NULL, NULL, 0), becase it may
+ * cause undefined behavior. We use a kind of cork stopper to avoid
+ * undefined behavior.
+ */
+ byte *buf = gcry_xcalloc (1, 1);
+ gcry_mpi_t a = gcry_mpi_set_opaque (NULL, buf, 1);
+ gcry_mpi_set_flag (a, GCRYMPI_FLAG_USER2);
+ return a;
+}
+
+
/* Read an external representation of an SOS and return the opaque MPI
with GCRYMPI_FLAG_USER2. The external format is a 16-bit unsigned
value stored in network byte order giving information for the
@@ -222,7 +238,12 @@ sos_read (iobuf_t inp, unsigned int *ret_nread, int secure)
goto leave;
++nread;
nbits |= c;
- if (nbits > MAX_EXTERN_MPI_BITS)
+ if (nbits == 0)
+ {
+ *ret_nread = nread;
+ return sos_zero ();
+ }
+ else if (nbits > MAX_EXTERN_MPI_BITS)
{
log_error ("mpi too large (%u bits)\n", nbits);
goto leave;
@@ -231,8 +252,6 @@ sos_read (iobuf_t inp, unsigned int *ret_nread, int secure)
nbytes = (nbits + 7) / 8;
if (nbytes)
buf = secure ? gcry_xmalloc_secure (nbytes) : gcry_xmalloc (nbytes);
- else
- buf = NULL;
p = buf;
for (i = 0; i < nbytes; i++)
{
@@ -2378,9 +2397,12 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
}
if (!sig->data[i])
rc = GPG_ERR_INV_PACKET;
- if (!pktlen && sig->pubkey_algo == PUBKEY_ALGO_EDDSA)
- /* Allow the R part only. */
- break;
+ if (i == 0 && !pktlen && sig->pubkey_algo == PUBKEY_ALGO_EDDSA)
+ {
+ /* Accept the case: R part only, missing S. */
+ sig->data[1] = sos_zero ();
+ break;
+ }
}
}
diff --git a/g10/pkglue.c b/g10/pkglue.c
index 019e5bac6..05bce14bf 100644
--- a/g10/pkglue.c
+++ b/g10/pkglue.c
@@ -319,15 +319,11 @@ pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash,
}
}
}
- /*
- * When data[1] is NULL or [0], parse the signature into R and S
- * parts.
- */
- else if (!s
- || (gcry_mpi_get_flag (s, GCRYMPI_FLAG_OPAQUE)
- && ((p = gcry_mpi_get_opaque (s, &nbits)) == NULL
- || nbits == 0
- || ((nbits+7)/8 == 1 && p[0] == 0))))
+ else if (gcry_mpi_get_flag (s, GCRYMPI_FLAG_OPAQUE)
+ && ((p = gcry_mpi_get_opaque (s, &nbits)) == NULL
+ || nbits == 0
+ || ((nbits+7)/8 == 1 && p[0] == 0)))
+ /* When data[1] is MPI(0), parse the signature into R and S parts. */
openpgp_ecc_parse_signature (pkalgo, r, &r, &s);
else
rc = 0;