summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
Diffstat (limited to 'ext')
-rw-r--r--ext/repo_pubkey.c114
-rw-r--r--ext/repo_pubkey.h1
-rw-r--r--ext/repo_rpmdb_librpm.h2
-rw-r--r--ext/solv_ed25519.h408
-rw-r--r--ext/solv_pgpvrfy.c259
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 */
}