summaryrefslogtreecommitdiffstats
path: root/g10
diff options
context:
space:
mode:
authorNIIBE Yutaka <gniibe@fsij.org>2021-12-10 07:39:32 +0100
committerNIIBE Yutaka <gniibe@fsij.org>2021-12-10 07:43:28 +0100
commit61ac580a2075564bc775b6764a239dad5e336251 (patch)
treefaccf5e0dea7b9c4a7dc7b9c29e4f6e564280d7e /g10
parentgpg: Fix function prototype to match declaration. (diff)
downloadgnupg2-61ac580a2075564bc775b6764a239dad5e336251.tar.xz
gnupg2-61ac580a2075564bc775b6764a239dad5e336251.zip
gpg: Emit compatible Ed25519 signature.
* g10/pkglue.c (sexp_extract_param_sos_nlz): New. * g10/pkglue.h: Add the declaration. * g10/sign.c (do_sign): Use sexp_extract_param_sos_nlz for Ed25519. -- Ed25519 signature in GnuPG 2.2 has no leading zeros. GnuPG-bug-id: 5331 Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
Diffstat (limited to 'g10')
-rw-r--r--g10/pkglue.c79
-rw-r--r--g10/pkglue.h2
-rw-r--r--g10/sign.c7
3 files changed, 87 insertions, 1 deletions
diff --git a/g10/pkglue.c b/g10/pkglue.c
index 1e0191e12..f18313913 100644
--- a/g10/pkglue.c
+++ b/g10/pkglue.c
@@ -47,8 +47,20 @@ get_mpi_from_sexp (gcry_sexp_t sexp, const char *item, int mpifmt)
}
+/*
+ * SOS (Simply, Octet String) is an attempt to handle opaque octet
+ * string in OpenPGP, where well-formed MPI cannot represent octet
+ * string with leading zero octets.
+ *
+ * To retain maximum compatibility to existing MPI handling, SOS
+ * has same structure, but allows leading zero octets. When there
+ * is no leading zero octets, SOS representation is as same as MPI one.
+ * With leading zero octets, NBITS is 8*(length of octets), regardless
+ * of leading zero bits.
+ */
/* Extract SOS representation from SEXP for PARAM, return the result
- in R_SOS. */
+ * in R_SOS. It is represented by opaque MPI with GCRYMPI_FLAG_USER2
+ * flag. */
gpg_error_t
sexp_extract_param_sos (gcry_sexp_t sexp, const char *param, gcry_mpi_t *r_sos)
{
@@ -98,6 +110,71 @@ sexp_extract_param_sos (gcry_sexp_t sexp, const char *param, gcry_mpi_t *r_sos)
}
+/* "No leading zero octets" (nlz) version of the function above.
+ *
+ * This routine is used for backward compatibility to existing
+ * implementation with the weird handling of little endian integer
+ * representation with leading zero octets. For the sake of
+ * "well-fomed" MPI, which is designed for big endian integer, leading
+ * zero octets are removed when output, and they are recovered at
+ * input.
+ *
+ * Extract SOS representation from SEXP for PARAM, removing leading
+ * zeros, return the result in R_SOS. */
+gpg_error_t
+sexp_extract_param_sos_nlz (gcry_sexp_t sexp, const char *param,
+ gcry_mpi_t *r_sos)
+{
+ gpg_error_t err;
+ gcry_sexp_t l2 = gcry_sexp_find_token (sexp, param, 0);
+
+ *r_sos = NULL;
+ if (!l2)
+ err = gpg_error (GPG_ERR_NO_OBJ);
+ else
+ {
+ size_t buflen;
+ const void *p0 = gcry_sexp_nth_data (l2, 1, &buflen);
+
+ if (!p0)
+ err = gpg_error_from_syserror ();
+ else
+ {
+ gcry_mpi_t sos;
+ unsigned int nbits = buflen*8;
+ const unsigned char *p = p0;
+
+ /* Strip leading zero bits. */
+ for (; nbits >= 8 && !*p; p++, nbits -= 8)
+ ;
+
+ if (nbits >= 8 && !(*p & 0x80))
+ if (--nbits >= 7 && !(*p & 0x40))
+ if (--nbits >= 6 && !(*p & 0x20))
+ if (--nbits >= 5 && !(*p & 0x10))
+ if (--nbits >= 4 && !(*p & 0x08))
+ if (--nbits >= 3 && !(*p & 0x04))
+ if (--nbits >= 2 && !(*p & 0x02))
+ if (--nbits >= 1 && !(*p & 0x01))
+ --nbits;
+
+ sos = gcry_mpi_set_opaque_copy (NULL, p, nbits);
+ if (sos)
+ {
+ gcry_mpi_set_flag (sos, GCRYMPI_FLAG_USER2);
+ *r_sos = sos;
+ err = 0;
+ }
+ else
+ err = gpg_error_from_syserror ();
+ }
+ gcry_sexp_release (l2);
+ }
+
+ return err;
+}
+
+
static byte *
get_data_from_sexp (gcry_sexp_t sexp, const char *item, size_t *r_size)
{
diff --git a/g10/pkglue.h b/g10/pkglue.h
index 308e54f9a..abeddb811 100644
--- a/g10/pkglue.h
+++ b/g10/pkglue.h
@@ -26,6 +26,8 @@
gcry_mpi_t get_mpi_from_sexp (gcry_sexp_t sexp, const char *item, int mpifmt);
gpg_error_t sexp_extract_param_sos (gcry_sexp_t sexp, const char *param,
gcry_mpi_t *r_sos);
+gpg_error_t sexp_extract_param_sos_nlz (gcry_sexp_t sexp, const char *param,
+ gcry_mpi_t *r_sos);
int pk_verify (pubkey_algo_t algo, gcry_mpi_t hash, gcry_mpi_t *data,
gcry_mpi_t *pkey);
diff --git a/g10/sign.c b/g10/sign.c
index ea3de620b..98cfcb2e3 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -506,6 +506,13 @@ do_sign (ctrl_t ctrl, PKT_public_key *pksk, PKT_signature *sig,
else if (pksk->pubkey_algo == GCRY_PK_RSA
|| pksk->pubkey_algo == GCRY_PK_RSA_S)
sig->data[0] = get_mpi_from_sexp (s_sigval, "s", GCRYMPI_FMT_USG);
+ else if (pksk->pubkey_algo == PUBKEY_ALGO_EDDSA
+ && openpgp_oid_is_ed25519 (pksk->pkey[0]))
+ {
+ err = sexp_extract_param_sos_nlz (s_sigval, "r", &sig->data[0]);
+ if (!err)
+ err = sexp_extract_param_sos_nlz (s_sigval, "s", &sig->data[1]);
+ }
else if (pksk->pubkey_algo == PUBKEY_ALGO_ECDSA
|| pksk->pubkey_algo == PUBKEY_ALGO_EDDSA)
{