Imported Upstream version 0.7.14
[platform/upstream/libsolv.git] / ext / solv_pgpvrfy.c
index a62ca13..8fec835 100644 (file)
@@ -1,11 +1,11 @@
 /*
- * Copyright (c) 2013, SUSE Inc.
+ * Copyright (c) 2013-2020, SUSE LLC.
  *
  * This program is licensed under the BSD license, read LICENSE.BSD
  * for further information
  */
 
-/* simple and slow rsa/dsa verification code. */
+/* simple and slow pgp signature verification code. */
 
 #include <stdio.h>
 #include <stdlib.h>
 #include "util.h"
 #include "solv_pgpvrfy.h"
 
+#ifndef ENABLE_PGPVRFY_ED25519
+#define ENABLE_PGPVRFY_ED25519 1
+#endif
+
 typedef unsigned int mp_t;
 typedef unsigned long long mp2_t;
 #define MP_T_BYTES 4
 
 #define MP_T_BITS (MP_T_BYTES * 8)
 
-static inline void
-mpzero(int len, mp_t *target)
-{
-  memset(target, 0, MP_T_BYTES * len);
-}
-
 static inline mp_t *
 mpnew(int len)
 {
@@ -33,11 +31,58 @@ mpnew(int len)
 }
 
 static inline void
+mpzero(int len, mp_t *target)
+{
+  memset(target, 0, MP_T_BYTES * len);
+}
+
+static inline void
 mpcpy(int len, mp_t *target, mp_t *source)
 {
   memcpy(target, source, len * MP_T_BYTES);
 }
 
+static void
+mpsetfrombe(int len, mp_t *target, const unsigned char *buf, int bufl)
+{
+  int i, mpl = len * MP_T_BYTES;
+  buf += bufl;
+  if (bufl >= mpl)
+    bufl = mpl;
+  if (mpl)
+    memset(target, 0, mpl);
+  for (i = 0; bufl > 0; bufl--, i++)
+    target[i / MP_T_BYTES] |= (int)(*--buf) << (8 * (i % MP_T_BYTES));
+}
+
+static int
+mpisless(int len, mp_t *a, mp_t *b)
+{
+  int i;
+  for (i = len - 1; i >= 0; i--)
+    if (a[i] < b[i])
+      return 1;
+    else if (a[i] > b[i])
+      return 0;
+  return 0;
+}
+
+static int
+mpisequal(int len, mp_t *a, mp_t *b)
+{
+  return memcmp(a, b, len * MP_T_BYTES) == 0;
+}
+
+static int
+mpiszero(int len, mp_t *a)
+{
+  int i;
+  for (i = 0; i < len; i++)
+    if (a[i])
+      return 0;
+  return 1;
+}
+
 #if 0
 static void mpdump(int l, mp_t *a, char *s)
 {
@@ -50,6 +95,19 @@ static void mpdump(int l, mp_t *a, char *s)
 }
 #endif
 
+/* subtract mod from target. target >= mod */
+static inline void mpsubmod(int len, mp_t *target, mp_t *mod)
+{
+  int i;
+  mp2_t n;
+  for (n = 0, i = 0; i < len; i++)
+    {
+      mp2_t n2 = (mp2_t)mod[i] + n;
+      n = n2 > target[i] ? 1 : 0;
+      target[i] -= (mp_t)n2;
+    }
+}
+
 /* target[len] = x, target = target % mod
  * assumes that target < (mod << MP_T_BITS)! */
 static void
@@ -70,6 +128,8 @@ mpdomod(int len, mp_t *target, mp2_t x, mp_t *mod)
       /* reduce */
       mp2_t z = x / ((mp2_t)mod[i] + 1);
       mp2_t n = 0;
+      if ((z >> MP_T_BITS) != 0)
+       z = (mp2_t)1 << MP_T_BITS;      /* just in case... */
       for (j = 0; j < i; j++)
        {
          mp_t n2;
@@ -84,31 +144,13 @@ mpdomod(int len, mp_t *target, mp2_t x, mp_t *mod)
       x -= n;
     }
   target[i] = x;
-  if (x >= mod[i])
-    {
-      mp_t n;
-      if (x == mod[i])
-       {
-         for (j = i - 1; j >= 0; j--)
-           if (target[j] < mod[j])
-             return;
-           else if (target[j] > mod[j])
-             break;
-       }
-      /* target >= mod, subtract mod */
-      n = 0;
-      for (j = 0; j <= i; j++)
-       {
-         mp2_t n2 = mod[j] + n;
-         n = n2 > target[j] ? 1 : 0;
-         target[j] -= (mp_t)n2;
-       }
-    }
+  if (x > mod[i] || (x == mod[i] && !mpisless(i, target, mod)))
+    mpsubmod(i + 1, target, mod);
 }
 
 /* target += src * m */
 static void
-mpmult_add_int(int len, mp_t *target, mp_t *src, mp2_t m, mp_t *mod)
+mpmul_add_int(int len, mp_t *target, mp_t *src, mp2_t m, mp_t *mod)
 {
   int i;
   mp2_t x = 0;
@@ -137,7 +179,7 @@ mpshift(int len, mp_t *target, mp_t *mod)
 
 /* target += m1 * m2 */
 static void
-mpmult_add(int len, mp_t *target, mp_t *m1, int m2len, mp_t *m2, mp_t *tmp, mp_t *mod)
+mpmul_add(int len, mp_t *target, mp_t *m1, int m2len, mp_t *m2, mp_t *tmp, mp_t *mod)
 {
   int i, j;
   for (j = m2len - 1; j >= 0; j--)
@@ -149,19 +191,19 @@ mpmult_add(int len, mp_t *target, mp_t *m1, int m2len, mp_t *m2, mp_t *tmp, mp_t
   for (i = 0; i < j; i++)
     {
       if (m2[i])
-        mpmult_add_int(len, target, tmp, m2[i], mod);
+       mpmul_add_int(len, target, tmp, m2[i], mod);
       mpshift(len, tmp, mod);
     }
   if (m2[i])
-    mpmult_add_int(len, target, tmp, m2[i], mod);
+    mpmul_add_int(len, target, tmp, m2[i], mod);
 }
 
 /* target = target * m */
 static void
-mpmult_inplace(int len, mp_t *target, mp_t *m, mp_t *tmp1, mp_t *tmp2, mp_t *mod)
+mpmul_inplace(int len, mp_t *target, mp_t *m, mp_t *tmp1, mp_t *tmp2, mp_t *mod)
 {
   mpzero(len, tmp1);
-  mpmult_add(len, tmp1, target, len, m, tmp2, mod);
+  mpmul_add(len, tmp1, target, len, m, tmp2, mod);
   mpcpy(len, target, tmp1);
 }
 
@@ -170,15 +212,15 @@ static void
 mppow_int(int len, mp_t *target, mp_t *t, mp_t *mod, int e)
 {
   mp_t *t2 = t + len * 16;
-  mpmult_inplace(len, target, target, t, t2, mod);
-  mpmult_inplace(len, target, target, t, t2, mod);
-  mpmult_inplace(len, target, target, t, t2, mod);
-  mpmult_inplace(len, target, target, t, t2, mod);
+  mpmul_inplace(len, target, target, t, t2, mod);
+  mpmul_inplace(len, target, target, t, t2, mod);
+  mpmul_inplace(len, target, target, t, t2, mod);
+  mpmul_inplace(len, target, target, t, t2, mod);
   if (e)
-    mpmult_inplace(len, target, t + len * e, t, t2, mod);
+    mpmul_inplace(len, target, t + len * e, t, t2, mod);
 }
 
-/* target = b ^ e (b has to be < mod) */
+/* target = b ^ e (b < mod) */
 static void
 mppow(int len, mp_t *target, mp_t *b, int elen, mp_t *e, mp_t *mod)
 {
@@ -194,7 +236,7 @@ mppow(int len, mp_t *target, mp_t *b, int elen, mp_t *e, mp_t *mod)
   t = mpnew(len * 17);
   mpcpy(len, t + len, b);
   for (j = 2; j < 16; j++)
-    mpmult_add(len, t + len * j, b, len, t + len * j - len, t + len * 16, mod);
+    mpmul_add(len, t + len * j, b, len, t + len * j - len, t + len * 16, mod);
   for (; i >= 0; i--)
     {
 #if MP_T_BYTES == 4
@@ -214,48 +256,67 @@ mppow(int len, mp_t *target, mp_t *b, int elen, mp_t *e, mp_t *mod)
   free(t);
 }
 
-/* target = m1 * m2 (m1 has to be < mod) */
+/* target = m1 * m2 (m1 < mod) */
 static void
-mpmult(int len, mp_t *target, mp_t *m1, int m2len, mp_t *m2, mp_t *mod)
+mpmul(int len, mp_t *target, mp_t *m1, int m2len, mp_t *m2, mp_t *mod)
 {
   mp_t *tmp = mpnew(len);
   mpzero(len, target);
-  mpmult_add(len, target, m1, m2len, m2, tmp, mod);
+  mpmul_add(len, target, m1, m2len, m2, tmp, mod);
   free(tmp);
 }
 
-static int
-mpisless(int len, mp_t *a, mp_t *b)
+static void
+mpdec(int len, mp_t *a)
 {
   int i;
-  for (i = len - 1; i >= 0; i--)
-    if (a[i] < b[i])
-      return 1;
-    else if (a[i] > b[i])
-      return 0;
-  return 0;
+  for (i = 0; i < len; i++)
+    if (a[i]--)
+      return;
 }
 
-static int
-mpiszero(int len, mp_t *a)
+#if ENABLE_PGPVRFY_ED25519
+/* target = m1 + m2 (m1, m2 < mod). target may be m1 or m2 */
+static void
+mpadd(int len, mp_t *target, mp_t *m1, mp_t *m2, mp_t *mod)
 {
   int i;
+  mp2_t x = 0;
   for (i = 0; i < len; i++)
-    if (a[i])
-      return 0;
-  return 1;
+    {
+      x += (mp2_t)m1[i] + m2[i];
+      target[i] = x;
+      x >>= MP_T_BITS;
+    }
+  if (x || target[len - 1] > mod[len - 1] ||
+      (target[len -1 ] == mod[len - 1] && !mpisless(len - 1, target, mod)))
+    mpsubmod(len, target, mod);
 }
 
+/* target = m1 - m2 (m1, m2 < mod). target may be m1 or m2 */
 static void
-mpdec(int len, mp_t *a)
+mpsub(int len, mp_t *target, mp_t *m1, mp_t *m2, mp_t *mod)
 {
   int i;
+  mp2_t x = 0;
   for (i = 0; i < len; i++)
-    if (a[i]--)
-      return;
-    else
-      a[i] = -(mp_t)1;
+    {
+      x = (mp2_t)m1[i] - m2[i] - x;
+      target[i] = x;
+      x = x & ((mp2_t)1 << MP_T_BITS) ? 1 : 0;
+    }
+  if (x)
+    {
+      for (x = 0, i = 0; i < len; i++)
+       {
+         x += (mp2_t)target[i] + mod[i];
+         target[i] = x;
+         x >>= MP_T_BITS;
+       }
+    }
 }
+#endif
+
 
 static int
 mpdsa(int pl, mp_t *p, int ql, mp_t *q, mp_t *g, mp_t *y, mp_t *r, mp_t *s, int hl, mp_t *h)
@@ -264,6 +325,7 @@ mpdsa(int pl, mp_t *p, int ql, mp_t *q, mp_t *g, mp_t *y, mp_t *r, mp_t *s, int
   mp_t *tmp;
   mp_t *u1, *u2;
   mp_t *gu1, *yu2;
+  int res;
 #if 0
   mpdump(pl, p, "p = ");
   mpdump(ql, q, "q = ");
@@ -284,41 +346,38 @@ mpdsa(int pl, mp_t *p, int ql, mp_t *q, mp_t *g, mp_t *y, mp_t *r, mp_t *s, int
   mpdec(ql, tmp);                      /* tmp-- */
   mpdec(ql, tmp);                      /* tmp-- */
   w = mpnew(ql);
-  mppow(ql, w, s, ql, tmp, q);         /* w = s ^ tmp (s ^ -1) */
+  mppow(ql, w, s, ql, tmp, q);         /* w = s ^ tmp (s ^ -1) */
   u1 = mpnew(pl);                      /* note pl */
   /* order is important here: h can be >= q */
-  mpmult(ql, u1, w, hl, h, q);         /* u1 = w * h */
+  mpmul(ql, u1, w, hl, h, q);          /* u1 = w * h */
   u2 = mpnew(ql);                      /* u2 = 0 */
-  mpmult(ql, u2, w, ql, r, q);         /* u2 = w * r */
+  mpmul(ql, u2, w, ql, r, q);          /* u2 = w * r */
   free(w);
   gu1 = mpnew(pl);
   yu2 = mpnew(pl);
   mppow(pl, gu1, g, ql, u1, p);                /* gu1 = g ^ u1 */
   mppow(pl, yu2, y, ql, u2, p);                /* yu2 = y ^ u2 */
-  mpmult(pl, u1, gu1, pl, yu2, p);     /* u1 = gu1 * yu2 */
+  mpmul(pl, u1, gu1, pl, yu2, p);      /* u1 = gu1 * yu2 */
   free(gu1);
   free(yu2);
   mpzero(ql, u2);
   u2[0] = 1;                           /* u2 = 1 */
-  mpmult(ql, tmp, u2, pl, u1, q);      /* tmp = u2 * u1 */
+  mpmul(ql, tmp, u2, pl, u1, q);       /* tmp = u2 * u1 */
   free(u1);
   free(u2);
 #if 0
   mpdump(ql, tmp, "res = ");
 #endif
-  if (memcmp(tmp, r, ql * MP_T_BYTES) != 0)
-    {
-      free(tmp);
-      return 0;
-    }
+  res = mpisequal(ql, tmp, r);
   free(tmp);
-  return 1;
+  return res;
 }
 
-static int 
+static int
 mprsa(int nl, mp_t *n, int el, mp_t *e, mp_t *m, mp_t *c)
 {
   mp_t *tmp;
+  int res;
 #if 0
   mpdump(nl, n, "n = ");
   mpdump(el, e, "e = ");
@@ -334,34 +393,24 @@ mprsa(int nl, mp_t *n, int el, mp_t *e, mp_t *m, mp_t *c)
 #if 0
   mpdump(nl, tmp, "res = ");
 #endif
-  if (memcmp(tmp, c, nl * MP_T_BYTES) != 0)
-    {
-      free(tmp);
-      return 0;
-    }
+  res = mpisequal(nl, tmp, c);
   free(tmp);
-  return 1;
+  return res;
 }
 
+#if ENABLE_PGPVRFY_ED25519
+# include "solv_ed25519.h"
+#endif
+
 /* create mp with size tbits from data with size dbits */
 static mp_t *
 mpbuild(const unsigned char *d, int dbits, int tbits, int *mplp)
 {
   int l = (tbits + MP_T_BITS - 1) / MP_T_BITS;
-  int dl, i;
-
   mp_t *out = mpnew(l ? l : 1);
   if (mplp)
     *mplp = l;
-  dl = (dbits + 7) / 8;
-  d += dl;
-  if (dbits > tbits)
-    dl = (tbits + 7) / 8;
-  for (i = 0; dl > 0; dl--, i++)
-    {
-      int x = *--d;
-      out[i / MP_T_BYTES] |= x << (8 * (i % MP_T_BYTES));
-    }
+  mpsetfrombe(l, out, d, (dbits + 7) / 8);
   return out;
 }
 
@@ -388,6 +437,8 @@ findmpi(const unsigned char **mpip, int *mpilp, int maxbits, int *outlen)
   return mpi + 2;
 }
 
+/* sig: 0:algo 1:hash 2-:mpidata */
+/* pub: 0:algo 1-:mpidata */
 int
 solv_pgpvrfy(const unsigned char *pub, int publ, const unsigned char *sig, int sigl)
 {
@@ -415,10 +466,18 @@ solv_pgpvrfy(const unsigned char *pub, int publ, const unsigned char *sig, int s
       hashl = 32;      /* SHA-256 */
       oid = (unsigned char *)"\023\060\061\060\015\006\011\140\206\110\001\145\003\004\002\001\005\000\004\040";
       break;
+    case 9:
+      hashl = 48;      /* SHA-384 */
+      oid = (unsigned char *)"\023\060\101\060\015\006\011\140\206\110\001\145\003\004\002\002\005\000\004\060";
+      break;
     case 10:
       hashl = 64;      /* SHA-512 */
       oid = (unsigned char *)"\023\060\121\060\015\006\011\140\206\110\001\145\003\004\002\003\005\000\004\100";
       break;
+    case 11:
+      hashl = 28;      /* SHA-224 */
+      oid = (unsigned char *)"\023\060\061\060\015\006\011\140\206\110\001\145\003\004\002\004\005\000\004\034";
+      break;
     default:
       return 0;                /* unsupported hash algo */
     }
@@ -505,6 +564,36 @@ solv_pgpvrfy(const unsigned char *pub, int publ, const unsigned char *sig, int s
        free(hx);
        break;
       }
+#if ENABLE_PGPVRFY_ED25519
+    case 22:           /* EdDSA */
+      {
+       unsigned char sigdata[64];
+       const unsigned char *r, *s;
+       int rlen, slen;
+
+       /* check the curve */
+       if (publ < 11 || memcmp(pub + 1, "\011\053\006\001\004\001\332\107\017\001", 10) != 0)
+         return 0;     /* we only support the Ed25519 curve */
+       /* the pubkey always has 7 + 256 bits */
+       if (publ != 1 + 10 + 2 + 1 + 32 || pub[1 + 10 + 0] != 1 || pub[1 + 10 + 1] != 7 || pub[1 + 10 + 2] != 0x40)
+         return 0;
+       mpi = sig + 2 + hashl;
+       mpil = sigl - (2 + hashl);
+       r = findmpi(&mpi, &mpil, 256, &rlen);
+       s = findmpi(&mpi, &mpil, 256, &slen);
+       if (!r || !s)
+         return 0;
+       memset(sigdata, 0, 64);
+       rlen = (rlen + 7) / 8;
+       slen = (slen + 7) / 8;
+       if (rlen)
+         memcpy(sigdata + 32 - rlen, r, rlen);
+       if (slen)
+         memcpy(sigdata + 64 - slen, s, rlen);
+       res = mped25519(pub + 1 + 10 + 2 + 1, sigdata, sig + 2, hashl);
+       break;
+      }
+#endif
     default:
       return 0;                /* unsupported pubkey algo */
     }