diff options
Diffstat (limited to 'ext')
-rw-r--r-- | ext/repo_pubkey.c | 114 | ||||
-rw-r--r-- | ext/repo_pubkey.h | 1 | ||||
-rw-r--r-- | ext/repo_rpmdb_librpm.h | 2 | ||||
-rw-r--r-- | ext/solv_ed25519.h | 408 | ||||
-rw-r--r-- | ext/solv_pgpvrfy.c | 259 |
5 files changed, 596 insertions, 188 deletions
diff --git a/ext/repo_pubkey.c b/ext/repo_pubkey.c index eb83839..883e13a 100644 --- a/ext/repo_pubkey.c +++ b/ext/repo_pubkey.c @@ -503,11 +503,12 @@ static int parsepubkey(Solvable *s, Repodata *data, unsigned char *p, int pl, int flags) { Repo *repo = s->repo; + Pool *pool = repo->pool; unsigned char *pstart = p; int tag, l; unsigned char keyid[8]; char subkeyofstr[17]; - unsigned int kcr = 0, maxex = 0, maxsigcr = 0; + unsigned int kcr = 0, maxex = 0, maxsigcr = 0, rpmsigcr = 0; unsigned char *pubkey = 0; int pubkeyl = 0; int insubkey = 0; @@ -524,10 +525,10 @@ parsepubkey(Solvable *s, Repodata *data, unsigned char *p, int pl, int flags) { /* finish old key */ if (kcr) - repodata_set_num(data, s - repo->pool->solvables, SOLVABLE_BUILDTIME, kcr); + repodata_set_num(data, s - pool->solvables, SOLVABLE_BUILDTIME, kcr); if (maxex && maxex != -1) - repodata_set_num(data, s - repo->pool->solvables, PUBKEY_EXPIRES, maxex); - s->name = pool_str2id(s->repo->pool, insubkey ? "gpg-subkey" : "gpg-pubkey", 1); + repodata_set_num(data, s - pool->solvables, PUBKEY_EXPIRES, maxex); + s->name = pool_str2id(pool, insubkey ? "gpg-subkey" : "gpg-pubkey", 1); s->evr = 1; s->arch = 1; if (userid && useridl) @@ -535,7 +536,7 @@ parsepubkey(Solvable *s, Repodata *data, unsigned char *p, int pl, int flags) char *useridstr = solv_malloc(useridl + 1); memcpy(useridstr, userid, useridl); useridstr[useridl] = 0; - setutf8string(data, s - repo->pool->solvables, SOLVABLE_SUMMARY, useridstr); + setutf8string(data, s - pool->solvables, SOLVABLE_SUMMARY, useridstr); free(useridstr); } if (pubdata) @@ -543,16 +544,16 @@ parsepubkey(Solvable *s, Repodata *data, unsigned char *p, int pl, int flags) char keyidstr[17]; char evr[8 + 1 + 8 + 1]; solv_bin2hex(keyid, 8, keyidstr); - repodata_set_str(data, s - repo->pool->solvables, PUBKEY_KEYID, keyidstr); + repodata_set_str(data, s - pool->solvables, PUBKEY_KEYID, keyidstr); /* build rpm-style evr */ strcpy(evr, keyidstr + 8); - sprintf(evr + 8, "-%08x", maxsigcr); - s->evr = pool_str2id(repo->pool, evr, 1); + sprintf(evr + 8, "-%08x", (flags & USE_RPM_PUBKEY_BUILTTIME) ? rpmsigcr : maxsigcr); + s->evr = pool_str2id(pool, evr, 1); } if (insubkey && *subkeyofstr) - repodata_set_str(data, s - repo->pool->solvables, PUBKEY_SUBKEYOF, subkeyofstr); + repodata_set_str(data, s - pool->solvables, PUBKEY_SUBKEYOF, subkeyofstr); if (pubdata) /* set data blob */ - repodata_set_binary(data, s - repo->pool->solvables, PUBKEY_DATA, pubdata, pubdatal); + repodata_set_binary(data, s - pool->solvables, PUBKEY_DATA, pubdata, pubdatal); if (!pl) break; if (!hl) @@ -565,7 +566,7 @@ parsepubkey(Solvable *s, Repodata *data, unsigned char *p, int pl, int flags) if (tag == 14 && pubdata && !insubkey) solv_bin2hex(keyid, 8, subkeyofstr); /* create new solvable for subkey */ - s = pool_id2solvable(repo->pool, repo_add_solvable(repo)); + s = pool_id2solvable(pool, repo_add_solvable(repo)); } p += hl; pl -= hl; @@ -616,7 +617,7 @@ parsepubkey(Solvable *s, Repodata *data, unsigned char *p, int pl, int flags) solv_chksum_add(h, q + 2, ql2); solv_chksum_free(h, fp); solv_bin2hex(fp, 16, fpx); - repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_FINGERPRINT, fpx); + repodata_set_str(data, s - pool->solvables, PUBKEY_FINGERPRINT, fpx); } } pubdata = p + 7; @@ -640,7 +641,7 @@ parsepubkey(Solvable *s, Repodata *data, unsigned char *p, int pl, int flags) solv_chksum_add(h, p, l); solv_chksum_free(h, fp); solv_bin2hex(fp, 20, fpx); - repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_FINGERPRINT, fpx); + repodata_set_str(data, s - pool->solvables, PUBKEY_FINGERPRINT, fpx); memcpy(keyid, fp + 12, 8); /* keyid is last 64 bits of fingerprint */ pubdata = p + 5; pubdatal = l - 5; @@ -664,6 +665,8 @@ parsepubkey(Solvable *s, Repodata *data, unsigned char *p, int pl, int flags) pgpsig_makesigdata(&sig, p, l, pubkey, pubkeyl, userid, useridl, h); solv_chksum_free(h, 0); } + if (!rpmsigcr) + rpmsigcr = sig.created; if (!memcmp(keyid, sig.issuer, 8)) { #ifdef ENABLE_PGPVRFY @@ -694,7 +697,7 @@ parsepubkey(Solvable *s, Repodata *data, unsigned char *p, int pl, int flags) repodata_set_num(data, shandle, SIGNATURE_EXPIRES, sig.created + sig.expires); if (sig.sigdata) repodata_set_binary(data, shandle, SIGNATURE_DATA, sig.sigdata, sig.sigdatal); - repodata_add_flexarray(data, s - s->repo->pool->solvables, PUBKEY_SIGNATURES, shandle); + repodata_add_flexarray(data, s - pool->solvables, PUBKEY_SIGNATURES, shandle); } solv_free(sig.sigdata); } @@ -711,83 +714,6 @@ parsepubkey(Solvable *s, Repodata *data, unsigned char *p, int pl, int flags) return p ? p - pstart : 0; } - -#ifdef ENABLE_RPMDB - -/* this is private to rpm, but rpm lacks an interface to retrieve - * the values. Sigh. */ -struct pgpDigParams_s { - const char * userid; - const unsigned char * hash; -#ifndef HAVE_PGPDIGGETPARAMS - const char * params[4]; -#endif - unsigned char tag; - unsigned char version; /*!< version number. */ - unsigned char time[4]; /*!< time that the key was created. */ - unsigned char pubkey_algo; /*!< public key algorithm. */ - unsigned char hash_algo; - unsigned char sigtype; - unsigned char hashlen; - unsigned char signhash16[2]; - unsigned char signid[8]; - unsigned char saved; -}; - -#ifndef HAVE_PGPDIGGETPARAMS -struct pgpDig_s { - struct pgpDigParams_s signature; - struct pgpDigParams_s pubkey; -}; -#endif - - -/* only rpm knows how to do the release calculation, we don't dare - * to recreate all the bugs in libsolv */ -static void -parsepubkey_rpm(Solvable *s, Repodata *data, unsigned char *pkts, int pktsl) -{ - Pool *pool = s->repo->pool; - struct pgpDigParams_s *digpubkey; - pgpDig dig = 0; - char keyid[16 + 1]; - char evrbuf[8 + 1 + 8 + 1]; - unsigned int btime; - -#ifndef RPM5 - dig = pgpNewDig(); -#else - dig = pgpDigNew(RPMVSF_DEFAULT, 0); -#endif - (void) pgpPrtPkts(pkts, pktsl, dig, 0); -#ifdef HAVE_PGPDIGGETPARAMS - digpubkey = pgpDigGetParams(dig, PGPTAG_PUBLIC_KEY); -#else - digpubkey = &dig->pubkey; -#endif - if (digpubkey) - { - btime = digpubkey->time[0] << 24 | digpubkey->time[1] << 16 | digpubkey->time[2] << 8 | digpubkey->time[3]; - solv_bin2hex(digpubkey->signid, 8, keyid); - solv_bin2hex(digpubkey->signid + 4, 4, evrbuf); - evrbuf[8] = '-'; - solv_bin2hex(digpubkey->time, 4, evrbuf + 9); - s->evr = pool_str2id(pool, evrbuf, 1); - repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_KEYID, keyid); - if (digpubkey->userid) - setutf8string(data, s - s->repo->pool->solvables, SOLVABLE_SUMMARY, digpubkey->userid); - if (btime) - repodata_set_num(data, s - s->repo->pool->solvables, SOLVABLE_BUILDTIME, btime); - } -#ifndef RPM5 - (void)pgpFreeDig(dig); -#else - (void)pgpDigFree(dig); -#endif -} - -#endif /* ENABLE_RPMDB */ - /* parse an ascii armored pubkey * adds multiple pubkeys if ADD_MULTIPLE_PUBKEYS is set */ static int @@ -809,9 +735,6 @@ pubkey2solvable(Pool *pool, Id p, Repodata *data, char *pubkey, int flags) { setutf8string(data, p, SOLVABLE_DESCRIPTION, pubkey); pl = parsepubkey(pool->solvables + p, data, pkts, pktsl, flags); -#ifdef ENABLE_RPMDB - parsepubkey_rpm(pool->solvables + p, data, pkts, pktsl); -#endif if (!pl || !(flags & ADD_MULTIPLE_PUBKEYS)) break; } @@ -988,9 +911,6 @@ add_one_pubkey(Pool *pool, Repo *repo, Repodata *data, unsigned char *pbuf, int char *descr = armor(pbuf, pbufl, "-----BEGIN PGP PUBLIC KEY BLOCK-----", "-----END PGP PUBLIC KEY BLOCK-----", solvversion); setutf8string(data, p, SOLVABLE_DESCRIPTION, descr); parsepubkey(pool->solvables + p, data, pbuf, pbufl, flags); -#ifdef ENABLE_RPMDB - parsepubkey_rpm(pool->solvables + p, data, pbuf, pbufl); -#endif } int diff --git a/ext/repo_pubkey.h b/ext/repo_pubkey.h index 26cf0e1..51946bf 100644 --- a/ext/repo_pubkey.h +++ b/ext/repo_pubkey.h @@ -12,6 +12,7 @@ #define ADD_WITH_SUBKEYS (1 << 9) #define ADD_MULTIPLE_PUBKEYS (1 << 10) #define ADD_WITH_KEYSIGNATURES (1 << 11) +#define USE_RPM_PUBKEY_BUILTTIME (1 << 12) extern int repo_add_rpmdb_pubkeys(Repo *repo, int flags); extern Id repo_add_pubkey(Repo *repo, const char *keyfile, int flags); diff --git a/ext/repo_rpmdb_librpm.h b/ext/repo_rpmdb_librpm.h index 34e6698..35a46fa 100644 --- a/ext/repo_rpmdb_librpm.h +++ b/ext/repo_rpmdb_librpm.h @@ -46,7 +46,7 @@ static void detect_dbpath(struct rpmdbstate *state) { state->dbpath = access_rootdir(state, "/var/lib/rpm", W_OK) == -1 - && access_rootdir(state, "/usr/share/rpm/Packages", R_OK) == 0 + && (access_rootdir(state, "/usr/share/rpm/Packages", R_OK) == 0 || access_rootdir(state, "/usr/share/rpm/rpmdb.sqlite", R_OK) == 0) ? "/usr/share/rpm" : "/var/lib/rpm"; } diff --git a/ext/solv_ed25519.h b/ext/solv_ed25519.h new file mode 100644 index 0000000..0772cee --- /dev/null +++ b/ext/solv_ed25519.h @@ -0,0 +1,408 @@ +/* + * Copyright (c) 2020, SUSE LLC. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* simple and slow ed25519 verification code. */ + +#ifndef LIBSOLV_CHKSUM_H +#include "chksum.h" +#endif + +#define MPED25519_LEN (32 / MP_T_BYTES) + +#if MP_T_BYTES == 4 +# define MPED25519_CONST1(x) (mp_t)x +#elif MP_T_BYTES == 1 +# define MPED25519_CONST1(x) (mp_t)(x >> 0), (mp_t)(x >> 8), (mp_t)(x >> 16), (mp_t)(x >> 24) +#endif + +#define MPED25519_CONST(a, b, c, d, e, f, g, h) { \ + MPED25519_CONST1(h), MPED25519_CONST1(g), MPED25519_CONST1(f), MPED25519_CONST1(e), \ + MPED25519_CONST1(d), MPED25519_CONST1(c), MPED25519_CONST1(b), MPED25519_CONST1(a) \ +} + +static mp_t ed25519_q[] = /* mod prime */ + MPED25519_CONST(0x7FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFED); +static mp_t ed25519_d[] = /* -(121665/121666) */ + MPED25519_CONST(0x52036CEE, 0x2B6FFE73, 0x8CC74079, 0x7779E898, 0x00700A4D, 0x4141D8AB, 0x75EB4DCA, 0x135978A3); +static mp_t ed25519_sqrtm1[] = /* sqrt(-1) */ + MPED25519_CONST(0x2B832480, 0x4FC1DF0B, 0x2B4D0099, 0x3DFBD7A7, 0x2F431806, 0xAD2FE478, 0xC4EE1B27, 0x4A0EA0B0); +static mp_t ed25519_l[] = /* order of base point */ + MPED25519_CONST(0x10000000, 0x00000000, 0x00000000, 0x00000000, 0x14DEF9DE, 0xA2F79CD6, 0x5812631A, 0x5CF5D3ED); +static mp_t ed25519_gx[] = /* base point */ + MPED25519_CONST(0x216936D3, 0xCD6E53FE, 0xC0A4E231, 0xFDD6DC5C, 0x692CC760, 0x9525A7B2, 0xC9562D60, 0x8F25D51A); +static mp_t ed25519_gy[] = /* base point */ + MPED25519_CONST(0x66666666, 0x66666666, 0x66666666, 0x66666666, 0x66666666, 0x66666666, 0x66666666, 0x66666658); +static mp_t ed25519_one[] = /* 1 */ + MPED25519_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001); + +/* small helpers to save some typing */ +static inline void +mped25519_add(mp_t *target, mp_t *m1, mp_t *m2) +{ + mpadd(MPED25519_LEN, target, m1, m2, ed25519_q); +} + +static inline void +mped25519_sub(mp_t *target, mp_t *m1, mp_t *m2) +{ + mpsub(MPED25519_LEN, target, m1, m2, ed25519_q); +} + +/* target = 512 bit input modulo ed25519_q */ +static void +mped25519_reduce512(mp_t *target, mp_t *a) +{ + int i; + mp2_t x; + + for (x = 0, i = 0; i < MPED25519_LEN; i++) + { + x += (mp2_t)a[i] + (mp2_t)a[i + MPED25519_LEN] * 38; + target[i] = x; + x >>= MP_T_BITS; + } + x *= 38; + if ((target[MPED25519_LEN - 1] & (1 << (MP_T_BITS - 1))) != 0) + { + x += 19; + target[MPED25519_LEN - 1] -= 1 << (MP_T_BITS - 1); + } + for (i = 0; x && i < MPED25519_LEN; i++) + { + x += (mp2_t)target[i]; + target[i] = x; + x >>= MP_T_BITS; + } + if (target[MPED25519_LEN - 1] > ed25519_q[MPED25519_LEN - 1] || + (target[MPED25519_LEN - 1] == ed25519_q[MPED25519_LEN - 1] && !mpisless(MPED25519_LEN - 1, target, ed25519_q))) + mpsubmod(MPED25519_LEN, target, ed25519_q); +} + +static void +mped25519_mul(mp_t *target, mp_t *m1, mp_t *m2) +{ + mp_t tmp[MPED25519_LEN * 2]; + int i, j; + mp2_t x; + + mpzero(MPED25519_LEN * 2, tmp); + for (i = 0; i < MPED25519_LEN; i++) + { + for (x = 0, j = 0; j < MPED25519_LEN; j++) + { + x += (mp2_t)tmp[i + j] + (mp2_t)m1[i] * m2[j]; + tmp[i + j] = x; + x >>= MP_T_BITS; + } + tmp[i + j] = x; + } + mped25519_reduce512(target, tmp); +} + +static inline void +mped25519_sqr(mp_t *target, mp_t *m) +{ + mped25519_mul(target, m, m); +} + +/* target = a ^ (2^252 - 4), a11 = a ^ 11 */ +static void +mped25519_pow_252_4(mp_t *target, mp_t *a, mp_t *a_11) +{ + static const int todo[16] = { 0, 5, 1, 10, 2, 20, 3, 10, 2, 50, 5, 100, 6, 50, 5, 2 }; + mp_t data[9][MPED25519_LEN]; + int i, j; + + mpcpy(MPED25519_LEN, target, a); + mped25519_sqr(target, target); + mpcpy(MPED25519_LEN, a_11, target); + mped25519_sqr(target, target); + mped25519_sqr(target, target); + mped25519_mul(data[0], target, a); /* data[0] = 9 */ + mped25519_mul(a_11, data[0], a_11); /* a_11 = 11 */ + mped25519_mul(target, a_11, a_11); /* target = 22 */ + for (i = 0; i < 8; i++) + { + mped25519_mul(target, target, data[todo[i * 2]]); + mpcpy(MPED25519_LEN, data[i + 1], target); + for (j = todo[i * 2 + 1]; j-- > 0;) + mped25519_sqr(target, target); + } +} + +/* target = a ^ (2^252 - 3) */ +static void +mped25519_pow_252_3(mp_t *target, mp_t *a) +{ + mp_t t11[MPED25519_LEN]; + mped25519_pow_252_4(target, a, t11); + mped25519_mul(target, target, a); +} + +/* target = a ^ -1 = a ^ (2^255 - 21) */ +static void +mped25519_inv(mp_t *target, mp_t *a) +{ + mp_t t[MPED25519_LEN], t11[MPED25519_LEN]; + mped25519_pow_252_4(t, a, t11); + mped25519_sqr(t, t); + mped25519_sqr(t, t); + mped25519_sqr(t, t); /* 2^255 - 32 */ + mped25519_mul(target, t, t11); +} + +static void +mped25519_reduce512_l(mp_t *target, mp_t *a) +{ + mp_t tmp[MPED25519_LEN]; + mpzero(MPED25519_LEN, target); + mpmul_add(MPED25519_LEN, target, ed25519_one, MPED25519_LEN * 2, a, tmp, ed25519_l); +} + +/* recover x coordinate from y and sign */ +static int +mped25519_recover_x(mp_t *x, mp_t *y, int sign) +{ + mp_t num[MPED25519_LEN], den[MPED25519_LEN]; + mp_t tmp1[MPED25519_LEN], tmp2[MPED25519_LEN]; + + if (!mpisless(MPED25519_LEN, y, ed25519_q)) + return 0; + /* calculate num=y^2-1 and den=dy^2+1 */ + mped25519_sqr(num, y); + mped25519_mul(den, num, ed25519_d); + mped25519_sub(num, num, ed25519_one); + mped25519_add(den, den, ed25519_one); + + /* calculate x = num*den^3 * (num*den^7)^((q-5)/8) */ + mped25519_sqr(tmp1, den); /* tmp1 = den^2 */ + mped25519_mul(tmp2, tmp1, den); /* tmp2 = den^3 */ + mped25519_sqr(tmp1, tmp2); /* tmp1 = den^6 */ + mped25519_mul(x, tmp1, den); /* x = den^7 */ + mped25519_mul(tmp1, x, num); /* tmp1 = num * den^7 */ + mped25519_pow_252_3(x, tmp1); /* x = tmp1^((q-5)/8) */ + mped25519_mul(tmp1, x, tmp2); /* tmp1 = x * den^3 */ + mped25519_mul(x, tmp1, num); /* x = tmp1 * num */ + + /* check if den*x^2 == num */ + mped25519_sqr(tmp2, x); + mped25519_mul(tmp1, tmp2, den); + if (!mpisequal(MPED25519_LEN, tmp1, num)) { + mped25519_mul(x, x, ed25519_sqrtm1); /* x = x * sqrt(-1) */ + mped25519_sqr(tmp2, x); + mped25519_mul(tmp1, tmp2, den); + if (!mpisequal(MPED25519_LEN, tmp1, num)) + return 0; + } + if (mpiszero(MPED25519_LEN, x)) + return 0; /* (0,1) is bad */ + if ((x[0] & 1) != sign) + mped25519_sub(x, ed25519_q, x); + return 1; +} + +/* see https://hyperelliptic.org/EFD/g1p/auto-twisted-projective.html */ +/* M=7 add=6 */ +static void +mped25519_ptdouble(mp_t *p_x, mp_t *p_y, mp_t *p_z) +{ + mp_t B[MPED25519_LEN], C[MPED25519_LEN], D[MPED25519_LEN]; + mp_t F[MPED25519_LEN], H[MPED25519_LEN], J[MPED25519_LEN]; + + mped25519_add(C, p_x, p_y); + mped25519_sqr(B, C); + mped25519_sqr(C, p_x); + mped25519_sqr(D, p_y); + mped25519_sub(F, C, D); + mped25519_sqr(H, p_z); + mped25519_add(H, H, H); + mped25519_add(J, F, H); + mped25519_add(H, C, D); + mped25519_mul(p_y, H, F); + mped25519_mul(p_z, J, F); + mped25519_sub(H, H, B); + mped25519_mul(p_x, J, H); +} + +/* M=12 add=7 */ +static void +mped25519_ptadd(mp_t *p_x, mp_t *p_y, mp_t *p_z, mp_t *q_x, mp_t *q_y, mp_t *q_z) +{ + mp_t A[MPED25519_LEN], B[MPED25519_LEN], C[MPED25519_LEN]; + mp_t D[MPED25519_LEN], E[MPED25519_LEN], F[MPED25519_LEN]; + mp_t G[MPED25519_LEN], H[MPED25519_LEN], J[MPED25519_LEN]; + + mped25519_mul(A, p_z, q_z); + mped25519_sqr(B, A); + mped25519_mul(C, p_x, q_x); + mped25519_mul(D, p_y, q_y); + mped25519_mul(F, ed25519_d, C); + mped25519_mul(E, F, D); + mped25519_sub(F, B, E); + mped25519_add(G, B, E); + mped25519_add(H, p_x, p_y); + mped25519_add(J, q_x, q_y); + mped25519_mul(p_x, H, J); + mped25519_sub(p_x, p_x, C); + mped25519_sub(p_x, p_x, D); + mped25519_mul(H, p_x, F); + mped25519_mul(p_x, H, A); + mped25519_add(H, D, C); + mped25519_mul(J, H, G); + mped25519_mul(p_y, J, A); + mped25519_mul(p_z, F, G); +} + +static inline void +mped25519_ptcpy(mp_t *p_x, mp_t *p_y, mp_t *p_z, mp_t *q_x, mp_t *q_y, mp_t *q_z) +{ + mpcpy(MPED25519_LEN, p_x, q_x); + mpcpy(MPED25519_LEN, p_y, q_y); + mpcpy(MPED25519_LEN, p_z, q_z); +} + +#if 0 +static void +mped25519_mpdump(mp_t *p, char *s, int c) +{ + if (c) + fprintf(stderr, "%c.", c); + mpdump(MPED25519_LEN, p, s); +} + +static void +mped25519_ptdump(mp_t *p_x, mp_t *p_y, mp_t *p_z, char *s) +{ + mp_t zi[MPED25519_LEN], px[MPED25519_LEN], py[MPED25519_LEN]; + mped25519_mpdump(p_x, s, 'X'); + mped25519_mpdump(p_y, s, 'Y'); + mped25519_mpdump(p_z, s, 'Z'); + mped25519_inv(zi, p_z); + mped25519_mul(px, p_x, zi); + mped25519_mul(py, p_y, zi); + mped25519_mpdump(px, s, 'x'); + mped25519_mpdump(py, s, 'y'); +} +#endif + + +/* scalar multiplication and add: r = s1*p1 + s2*p2 */ +/* needs about 13 + (256 - 32) / 2 = 125 point additions */ +static int +mped25519_scmult2(mp_t *r_x, mp_t *r_y, mp_t *s1, mp_t *p1_x, mp_t * p1_y, mp_t *s2, mp_t *p2_x, mp_t * p2_y) +{ + mp_t p_x[MPED25519_LEN], p_y[MPED25519_LEN], p_z[MPED25519_LEN]; + mp_t pi_z[MPED25519_LEN]; + mp_t tabx[16][MPED25519_LEN], taby[16][MPED25519_LEN], tabz[16][MPED25519_LEN]; + int i, x, dodouble = 0; + + mpzero(MPED25519_LEN, p_x); + mpzero(MPED25519_LEN, p_y); + mpzero(MPED25519_LEN, p_z); + p_y[0] = p_z[0] = 1; + + /* setup table: tab[i * 4 + j] = i * p1 + j * p2 */ + mped25519_ptcpy(tabx[0], taby[0], tabz[0], p_x, p_y, p_z); + for (i = 4; i < 16; i += 4) + mped25519_ptcpy(tabx[i], taby[i], tabz[i], p1_x, p1_y, ed25519_one); + mped25519_ptdouble(tabx[8], taby[8], tabz[8]); + mped25519_ptadd(tabx[12], taby[12], tabz[12], tabx[8], taby[8], tabz[8]); + mped25519_ptcpy(tabx[1], taby[1], tabz[1], p2_x, p2_y, ed25519_one); + for (i = 2; i < 16; i++) + { + if ((i & 3) == 0) + continue; + mped25519_ptcpy(tabx[i], taby[i], tabz[i], tabx[i - 1], taby[i - 1], tabz[i - 1]); + mped25519_ptadd(tabx[i], taby[i], tabz[i], p2_x, p2_y, ed25519_one); + } + /* now do the scalar multiplication */ + for (i = 255; i >= 0; i--) + { + if (dodouble) + mped25519_ptdouble(p_x, p_y, p_z); + x = s1[i / MP_T_BITS] & (1 << (i % MP_T_BITS)) ? 4 : 0; + x |= s2[i / MP_T_BITS] & (1 << (i % MP_T_BITS)) ? 1 : 0; + if (!x) + continue; + if (i > 0) + { + i--; + if (dodouble) + mped25519_ptdouble(p_x, p_y, p_z); + x <<= 1; + x |= s1[i / MP_T_BITS] & (1 << (i % MP_T_BITS)) ? 4 : 0; + x |= s2[i / MP_T_BITS] & (1 << (i % MP_T_BITS)) ? 1 : 0; + } + mped25519_ptadd(p_x, p_y, p_z, tabx[x], taby[x], tabz[x]); + dodouble = 1; + } +#if 0 + mped25519_ptdump(p_x, p_y, p_z, "r = "); +#endif + mped25519_inv(pi_z, p_z); + mped25519_mul(r_x, p_x, pi_z); + mped25519_mul(r_y, p_y, pi_z); + return mpiszero(MPED25519_LEN, p_z) ? 0 : 1; +} + +static void +mped25519_setfromle(int len, mp_t *out, const unsigned char *buf, int bufl, int highmask) +{ + unsigned char bebuf[64]; /* bufl must be <= 64 */ + int i; + for (i = 0; i < bufl; i++) + bebuf[bufl - 1 - i] = buf[i]; + bebuf[0] &= highmask; + mpsetfrombe(len, out, bebuf, bufl); +} + +static int +mped25519(const unsigned char *pub, const unsigned char *sig, const unsigned char *data, unsigned int datal) +{ + unsigned char hbuf[64], rbuf[32]; + int i; + mp_t pub_x[MPED25519_LEN], pub_y[MPED25519_LEN]; + mp_t h[MPED25519_LEN], s[MPED25519_LEN], h2[MPED25519_LEN * 2]; + mp_t r_x[MPED25519_LEN], r_y[MPED25519_LEN]; + Chksum *chk; + + mped25519_setfromle(MPED25519_LEN, s, sig + 32, 32, 0xff); + if (!mpisless(MPED25519_LEN, s, ed25519_l)) + return 0; /* bad s */ + /* uncompress pubkey, we invert the sign to get -pub */ + mped25519_setfromle(MPED25519_LEN, pub_y, pub, 32, 0x7f); + if (!mped25519_recover_x(pub_x, pub_y, pub[31] & 0x80 ? 0 : 1)) + return 0; /* bad pubkey */ +#if 0 + mped25519_mpdump(pub_x, "-pubx = ", 0); + mped25519_mpdump(pub_y, "puby = ", 0); +#endif + /* calculate h = H(sig[0..31]|pub|data) mod l */ + chk = solv_chksum_create(REPOKEY_TYPE_SHA512); + if (!chk) + return 0; + solv_chksum_add(chk, sig, 32); + solv_chksum_add(chk, pub, 32); + solv_chksum_add(chk, data, datal); + solv_chksum_free(chk, hbuf); + mped25519_setfromle(MPED25519_LEN * 2, h2, hbuf, 64, 0xff); + mped25519_reduce512_l(h, h2); +#if 0 + mped25519_mpdump(s, "s = ", 0); + mped25519_mpdump(h, "h = ", 0); +#endif + /* calculate r = s * G - h * pub */ + if (!mped25519_scmult2(r_x, r_y, s, ed25519_gx, ed25519_gy, h, pub_x, pub_y)) + return 0; + /* compress r into rbuf and verify that it matches sig */ + for (i = 0; i < 32; i++) + rbuf[i] = r_y[i / MP_T_BYTES] >> (8 * (i % MP_T_BYTES)); + if ((r_x[0] & 1) != 0) + rbuf[31] |= 0x80; + return memcmp(sig, rbuf, 32) == 0 ? 1 : 0; +} + diff --git a/ext/solv_pgpvrfy.c b/ext/solv_pgpvrfy.c index 9bc256c..8fec835 100644 --- a/ext/solv_pgpvrfy.c +++ b/ext/solv_pgpvrfy.c @@ -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> @@ -14,18 +14,16 @@ #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 @@ -86,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; @@ -139,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--) @@ -151,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); } @@ -172,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) { @@ -196,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 @@ -216,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) @@ -266,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 = "); @@ -286,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 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 = "); @@ -336,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; } @@ -390,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) { @@ -515,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 */ } |