]> git.ipfire.org Git - thirdparty/libsolv.git/commitdiff
add slow but small dsa/rsa implementation
authorMichael Schroeder <mls@suse.de>
Thu, 25 Jul 2013 15:12:25 +0000 (17:12 +0200)
committerMichael Schroeder <mls@suse.de>
Thu, 25 Jul 2013 15:39:15 +0000 (17:39 +0200)
CMakeLists.txt
ext/CMakeLists.txt
ext/solv_pgpvrfy.c [new file with mode: 0644]
ext/solv_pgpvrfy.h [new file with mode: 0644]

index 16dde94b41059a4e93f3eaf97f4c9dbcca4542ee..0fb47310431c7551731b0eea37702e0a7b213ff4 100644 (file)
@@ -186,6 +186,10 @@ IF (ENABLE_RPMDB)
   CHECK_LIBRARY_EXISTS(rpmio pgpDigGetParams "" HAVE_PGPDIGGETPARAMS)
 ENDIF (ENABLE_RPMDB)
 
+IF (ENABLE_RPMDB_PUBKEY)
+  SET (ENABLE_PGPVRFY ON)
+ENDIF (ENABLE_RPMDB_PUBKEY)
+
 INCLUDE (CheckFunctionExists)
 INCLUDE (TestBigEndian)
 
@@ -199,7 +203,7 @@ FOREACH (VAR HAVE_STRCHRNUL HAVE_FOPENCOOKIE HAVE_FUNOPEN WORDS_BIGENDIAN
   HAVE_RPM_DB_H HAVE_PGPDIGGETPARAMS
   ENABLE_RPMDB ENABLE_RPMDB_PUBKEY ENABLE_RPMMD ENABLE_SUSEREPO ENABLE_COMPS
   ENABLE_HELIXREPO ENABLE_MDKREPO ENABLE_ARCHREPO ENABLE_DEBIAN ENABLE_HAIKU
-  ENABLE_LZMA_COMPRESSION ENABLE_BZIP2_COMPRESSION)
+  ENABLE_LZMA_COMPRESSION ENABLE_BZIP2_COMPRESSION ENABLE_PGPVRFY)
   IF(${VAR})
     ADD_DEFINITIONS (-D${VAR}=1)
     SET (SWIG_FLAGS ${SWIG_FLAGS} -D${VAR})
index e72da54e2588ad7d39a6470c5d36aa60b1f4c436..ccec994e4eaa1590852ceab162ed4c77d7719af8 100644 (file)
@@ -18,6 +18,13 @@ IF (ENABLE_RPMDB_PUBKEY)
        repo_rpmdb_pubkey.h)
 ENDIF (ENABLE_RPMDB_PUBKEY)
 
+IF (ENABLE_PGPVRFY)
+    SET (libsolvext_SRCS ${libsolvext_SRCS}
+       solv_pgpvrfy.c)
+    SET (libsolvext_HEADERS ${libsolvext_SRCS}
+       solv_pgpvrfy.h)
+ENDIF (ENABLE_PGPVRFY)
+
 IF (ENABLE_RPMMD)
     SET (libsolvext_SRCS ${libsolvext_SRCS}
        repo_repomdxml.c repo_rpmmd.c
diff --git a/ext/solv_pgpvrfy.c b/ext/solv_pgpvrfy.c
new file mode 100644 (file)
index 0000000..a4c819b
--- /dev/null
@@ -0,0 +1,500 @@
+/*
+ * Copyright (c) 2013, SUSE Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/* simple and slow rsa/dsa verification code. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+#include "solv_pgpvrfy.h"
+
+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)
+{
+  return solv_calloc(len, MP_T_BYTES);
+}
+
+/* target[len] = x, target = target % mod */
+static void
+mpdomod(int len, mp_t *target, mp2_t x, mp_t *mod)
+{
+  int i, j;
+  /* assumes that x does not overflow, i.e. target is not much bigger than mod! */
+  for (i = len - 1; i >= 0; i--)
+    {
+      x = (x << MP_T_BITS) | target[i];
+      target[i] = 0;
+      if (mod[i])
+       break;
+    }
+  if (i < 0)
+    return;
+  while (x >= 2 * (mp2_t)mod[i])
+    {
+      /* reduce */
+      mp2_t z = x / ((mp2_t)mod[i] + 1);
+      mp2_t n = 0;
+      for (j = 0; j < i; j++)
+       {
+         mp_t n2;
+         n += mod[j] * z;
+         n2 = (mp_t)n;
+         n >>= MP_T_BITS;
+         if (n2 > target[j])
+           n++;
+         target[j] -= n2;
+       }
+      n += mod[j] * z;
+      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;
+       }
+    }
+}
+
+/* target += src * m */
+static void
+mpmult_add_int(int len, mp_t *target, mp_t *src, mp2_t m, mp_t *mod)
+{
+  int i;
+  mp2_t x = 0;
+  for (i = 0; i < len; i++)
+    {
+      x += src[i] * m + target[i];
+      target[i] = x;
+      x >>= MP_T_BITS;
+    }
+  mpdomod(len, target, x, mod);
+}
+
+/* target = target * 2^MP_T_BITS */
+static void
+mpshift(int len, mp_t *target, mp_t *mod)
+{
+  mp_t x;
+  if (len <= 0)
+    return;
+  x = target[len - 1];
+  if (len > 1)
+    memmove(target + 1, target, (len - 1) * MP_T_BYTES);
+  target[0] = 0;
+  mpdomod(len, target, x, mod);
+}
+
+/* target += m1 * m2 */
+static void
+mpmult_add(int len, mp_t *target, mp_t *m1, int m2len, mp_t *m2, mp_t *mod)
+{
+  int i, j;
+  mp_t *t;
+  for (j = m2len - 1; j >= 0; j--)
+    if (m2[j])
+      break;
+  if (j < 0)
+    return;
+  t = mpnew(len);
+  memcpy(t, m1, len * MP_T_BYTES);
+  for (i = 0; i < j; i++)
+    {
+      if (m2[i])
+        mpmult_add_int(len, target, t, m2[i], mod);
+      mpshift(len, t, mod);
+    }
+  if (m2[i])
+    mpmult_add_int(len, target, t, m2[i], mod);
+  free(t);
+}
+
+/* target = target * m */
+static void
+mpmult_inplace(int len, mp_t *target, mp_t *m, mp_t *tmp, mp_t *mod)
+{
+  mpzero(len, tmp);
+  mpmult_add(len, tmp, target, len, m, mod);
+  memcpy(target, tmp, len * MP_T_BYTES);
+}
+
+/* target = target ^ (16 + e) */
+static void
+mppow_int(int len, mp_t *target, mp_t *t, mp_t *mod, int e)
+{
+  mpmult_inplace(len, target, target, t, mod);
+  mpmult_inplace(len, target, target, t, mod);
+  mpmult_inplace(len, target, target, t, mod);
+  mpmult_inplace(len, target, target, t, mod);
+  if (e)
+    mpmult_inplace(len, target, t + len * e, t, mod);
+}
+
+/* target = b ^ e */
+static void
+mppow(int len, mp_t *target, mp_t *b, int elen, mp_t *e, mp_t *mod)
+{
+  int i, j;
+  mp_t *t;
+  mpzero(len, target);
+  target[0] = 1;
+  for (i = elen - 1; i >= 0; i--)
+    if (e[i])
+      break;
+  if (i < 0)
+    return;
+  t = mpnew(len * 16);
+  memcpy(t + len, b, len * MP_T_BYTES);
+  for (j = 2; j < 16; j++)
+    mpmult_add(len, t + len * j, b, len, t + len * j - len, mod);
+  for (; i >= 0; i--)
+    {
+#if MP_T_BYTES == 4
+      mppow_int(len, target, t, mod, (e[i] >> 28) & 0x0f);
+      mppow_int(len, target, t, mod, (e[i] >> 24) & 0x0f);
+      mppow_int(len, target, t, mod, (e[i] >> 20) & 0x0f);
+      mppow_int(len, target, t, mod, (e[i] >> 16) & 0x0f);
+      mppow_int(len, target, t, mod, (e[i] >> 12) & 0x0f);
+      mppow_int(len, target, t, mod, (e[i] >>  8) & 0x0f);
+      mppow_int(len, target, t, mod, (e[i] >>  4) & 0x0f);
+      mppow_int(len, target, t, mod,  e[i]        & 0x0f);
+#elif MP_T_BYTES == 1
+      mppow_int(len, target, t, mod, (e[i] >>  4) & 0x0f);
+      mppow_int(len, target, t, mod,  e[i]        & 0x0f);
+#endif
+    }
+  free(t);
+}
+
+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
+mpiszero(int len, mp_t *a)
+{
+  int i;
+  for (i = 0; i < len; i++)
+    if (a[i])
+      return 0;
+  return 1;
+}
+
+static void
+mpdec(int len, mp_t *a)
+{
+  int i;
+  for (i = 0; i < len; i++)
+    if (a[i]--)
+      return;
+    else
+      a[i] = -(mp_t)1;
+}
+
+#if 0
+static void mpdump(int l, mp_t *a, char *s)
+{
+  int i;
+  if (s)
+    fprintf(stderr, "%s", s);
+  for (i = l - 1; i >= 0; i--)
+    fprintf(stderr, "%08x", a[i]);
+  fprintf(stderr, "\n");
+}
+#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)
+{
+  mp_t *w;
+  mp_t *tmp;
+  mp_t *u1, *u2;
+  mp_t *gu1, *yu2;
+#if 0
+  mpdump(pl, p, "p = ");
+  mpdump(ql, q, "q = ");
+  mpdump(pl, g, "g = ");
+  mpdump(pl, y, "y = ");
+  mpdump(ql, r, "r = ");
+  mpdump(ql, s, "s = ");
+  mpdump(hl, h, "h = ");
+#endif
+  if (pl < ql || !mpisless(pl, g, p) || !mpisless(pl, y, p))
+    return 0;                          /* hmm, bad pubkey? */
+  if (!mpisless(ql, r, q) || mpiszero(ql, r))
+    return 0;
+  if (!mpisless(ql, s, q) || mpiszero(ql, s))
+    return 0;
+  tmp = mpnew(pl);                     /* note pl! */
+  memcpy(tmp, q, ql * MP_T_BYTES);     /* tmp = q */
+  mpdec(ql, tmp);                      /* tmp-- */
+  mpdec(ql, tmp);                      /* tmp-- */
+  w = mpnew(ql);
+  mppow(ql, w, s, ql, tmp, q);         /* w = s ^ tmp (s ^ -1) */
+  u1 = mpnew(pl);                      /* u1 = 0 */
+  /* order is important here: h can be >= q */
+  mpmult_add(ql, u1, w, hl, h, q);     /* u1 += w * h */
+  u2 = mpnew(pl);                      /* u2 = 0 */
+  mpmult_add(ql, u2, w, ql, r, q);     /* u2 += w * r */
+  free(w);
+  gu1 = mpnew(pl);
+  yu2 = mpnew(pl);
+  mppow(pl, gu1, g, pl, u1, p);                /* gu1 = g ^ u1 */
+  mppow(pl, yu2, y, pl, u2, p);                /* yu2 = y ^ u2 */
+  mpzero(pl, u1);                      /* u1 = 0 */
+  mpmult_add(pl, u1, gu1, pl, yu2, p); /* u1 += gu1 * yu2 */
+  free(gu1);
+  free(yu2);
+  mpzero(ql, u2);
+  u2[0] = 1;                           /* u2 = 1 */
+  mpzero(ql, tmp);                     /* tmp = 0 */
+  mpmult_add(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;
+    }
+  free(tmp);
+  return 1;
+}
+
+static int 
+mprsa(int nl, mp_t *n, int el, mp_t *e, mp_t *m, mp_t *c)
+{
+  mp_t *tmp;
+#if 0
+  mpdump(nl, n, "n = ");
+  mpdump(el, e, "e = ");
+  mpdump(nl, m, "m = ");
+  mpdump(nl, c, "c = ");
+#endif
+  if (!mpisless(nl, m, n))
+    return 0;
+  if (!mpisless(nl, c, n))
+    return 0;
+  tmp = mpnew(nl);
+  mppow(nl, tmp, m, el, e, n);         /* tmp = m ^ e */
+#if 0
+  mpdump(nl, tmp, "res = ");
+#endif
+  if (memcmp(tmp, c, nl * MP_T_BYTES) != 0)
+    {
+      free(tmp);
+      return 0;
+    }
+  free(tmp);
+  return 1;
+}
+
+/* create mp with size tbits from data with size dbits */
+static mp_t *
+mpbuild(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));
+    }
+  return out;
+}
+
+static unsigned char *
+findmpi(unsigned char **mpip, int *mpilp, int maxbits, int *outlen)
+{
+  int mpil = *mpilp;
+  unsigned char *mpi = *mpip;
+  unsigned char *out = 0;
+  int bits, l;
+
+  if (mpil < 2)
+    return 0;
+  bits = mpi[0] << 8 | mpi[1];
+  l = 2 + (bits + 7) / 8;
+  if (bits > maxbits || mpil < l)
+    *mpilp = 0;
+  else
+    {
+      out = mpi + 2;
+      *outlen = bits;
+      *mpilp = mpil - l;
+      *mpip = mpi + l;
+    }
+  return out;
+}
+
+int
+solv_pgpvrfy(unsigned char *pub, int publ, unsigned char *sig, int sigl)
+{
+  int hashl;
+  unsigned char *oid = 0;
+  unsigned char *mpi;
+  int mpil;
+  int res = 0;
+
+  if (!pub || !sig || publ < 1 || sigl < 2)
+    return 0;
+  if (pub[0] != sig[0])
+    return 0;          /* key algo mismatch */
+  switch(sig[1])
+    {
+    case 1:
+      hashl = 16;      /* MD5 */
+      oid = (unsigned char *)"\022\060\040\060\014\006\010\052\206\110\206\367\015\002\005\005\000\004\020";
+      break;
+    case 2:
+      hashl = 20;      /* SHA-1 */
+      oid = (unsigned char *)"\017\060\041\060\011\006\005\053\016\003\002\032\005\000\004\024";
+      break;
+    case 8:
+      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 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;
+    default:
+      return 0;                /* unsupported hash algo */
+    }
+  if (sigl < 2 + hashl)
+    return 0;
+  switch (pub[0])
+    {
+    case 1:            /* RSA */
+      {
+       unsigned char *n, *e, *m, *c;
+       int nlen, elen, mlen, clen;
+       mp_t *nx, *ex, *mx, *cx;
+       int nxl, exl;
+
+        mpi = pub + 1;
+        mpil = publ - 1;
+       n = findmpi(&mpi, &mpil, 8192, &nlen);
+       e = findmpi(&mpi, &mpil, 1024, &elen);
+        mpi = sig + 2 + hashl;
+        mpil = sigl - (2 + hashl);
+       m = findmpi(&mpi, &mpil, nlen, &mlen);
+        if (!n || !e || !m || !nlen || !elen)
+         return 0;
+       /* build padding block */
+       clen = (nlen - 1) / 8;
+       if (hashl + *oid + 2 > clen)
+         return 0;
+       c = solv_malloc(clen);
+       memset(c, 0xff, clen);
+       c[0] = 1;
+       memcpy(c + clen - hashl, sig + 2, hashl);
+       memcpy(c + clen - hashl - *oid, oid + 1, *oid);
+       c[clen - hashl - *oid - 1] = 0;
+       clen = clen * 8 - 7;    /* always <= nlen */
+       nx = mpbuild(n, nlen, nlen, &nxl);
+       ex = mpbuild(e, elen, elen, &exl);
+       mx = mpbuild(m, mlen, nlen, 0);
+       cx = mpbuild(c, clen, nlen, 0);
+       free(c);
+       res = mprsa(nxl, nx, exl, ex, mx, cx);
+       free(nx);
+       free(ex);
+       free(mx);
+       free(cx);
+       break;
+      }
+    case 17:           /* DSA */
+      {
+       unsigned char *p, *q, *g, *y, *r, *s;
+       int plen, qlen, glen, ylen, rlen, slen, hlen;
+       mp_t *px, *qx, *gx, *yx, *rx, *sx, *hx;
+       int pxl, qxl, hxl;
+
+        mpi = pub + 1;
+        mpil = publ - 1;
+       p = findmpi(&mpi, &mpil, 8192, &plen);
+       q = findmpi(&mpi, &mpil, 1024, &qlen);
+       g = findmpi(&mpi, &mpil, plen, &glen);
+       y = findmpi(&mpi, &mpil, plen, &ylen);
+        mpi = sig + 2 + hashl;
+        mpil = sigl - (2 + hashl);
+       r = findmpi(&mpi, &mpil, qlen, &rlen);
+       s = findmpi(&mpi, &mpil, qlen, &slen);
+        if (!p || !q || !g || !y || !r || !s || !plen || !qlen)
+         return 0;
+       hlen = (qlen + 7) & ~7;
+       if (hlen > hashl * 8)
+         return 0;
+       px = mpbuild(p, plen, plen, &pxl);
+       qx = mpbuild(q, qlen, qlen, &qxl);
+       gx = mpbuild(g, glen, plen, 0);
+       yx = mpbuild(y, ylen, plen, 0);
+       rx = mpbuild(r, rlen, qlen, 0);
+       sx = mpbuild(s, slen, qlen, 0);
+       hx = mpbuild(sig + 2, hlen, hlen, &hxl);
+        res = mpdsa(pxl, px, qxl, qx, gx, yx, rx, sx, hxl, hx);
+       free(px);
+       free(qx);
+       free(gx);
+       free(yx);
+       free(rx);
+       free(sx);
+       free(hx);
+       break;
+      }
+    default:
+      return 0;                /* unsupported pubkey algo */
+    }
+  return res;
+}
+
diff --git a/ext/solv_pgpvrfy.h b/ext/solv_pgpvrfy.h
new file mode 100644 (file)
index 0000000..9959ddd
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * Copyright (c) 2013, SUSE Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+extern int solv_pgpvrfy(unsigned char *pub, int publ, unsigned char *sig, int sigl);
+