From: Michael Schroeder Date: Thu, 25 Jul 2013 15:12:25 +0000 (+0200) Subject: add slow but small dsa/rsa implementation X-Git-Tag: BASE-SuSE-Code-13_1-Branch~49 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3e5c879f1b770ad664b45f4eb73d254b5188ceee;p=thirdparty%2Flibsolv.git add slow but small dsa/rsa implementation --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 16dde94b..0fb47310 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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}) diff --git a/ext/CMakeLists.txt b/ext/CMakeLists.txt index e72da54e..ccec994e 100644 --- a/ext/CMakeLists.txt +++ b/ext/CMakeLists.txt @@ -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 index 00000000..a4c819bf --- /dev/null +++ b/ext/solv_pgpvrfy.c @@ -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 +#include +#include + +#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 index 00000000..9959ddd6 --- /dev/null +++ b/ext/solv_pgpvrfy.h @@ -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); +