Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support ed25519 signatures #1202

Merged
merged 3 commits into from May 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion rpmio/digest.h
Expand Up @@ -14,6 +14,7 @@ struct pgpDigAlg_s {
setmpifunc setmpi;
verifyfunc verify;
freefunc free;
int curve;
int mpis;
void *data; /*!< algorithm specific private data */
};
Expand Down Expand Up @@ -42,7 +43,7 @@ struct pgpDigParams_s {
pgpDigAlg alg;
};

pgpDigAlg pgpPubkeyNew(int algo);
pgpDigAlg pgpPubkeyNew(int algo, int curve);

pgpDigAlg pgpSignatureNew(int algo);

Expand Down
2 changes: 1 addition & 1 deletion rpmio/digest_beecrypt.c
Expand Up @@ -454,7 +454,7 @@ static int pgpVerifyNULL(pgpDigAlg pgpkey, pgpDigAlg pgpsig,
return 1;
}

pgpDigAlg pgpPubkeyNew(int algo)
pgpDigAlg pgpPubkeyNew(int algo, int curve)
{
pgpDigAlg ka = xcalloc(1, sizeof(*ka));;

Expand Down
147 changes: 146 additions & 1 deletion rpmio/digest_libgcrypt.c
Expand Up @@ -346,6 +346,117 @@ static void pgpFreeKeyDSA(pgpDigAlg pgpkey)
}


/****************************** EDDSA **************************************/

struct pgpDigSigEDDSA_s {
gcry_mpi_t r;
gcry_mpi_t s;
};

struct pgpDigKeyEDDSA_s {
gcry_mpi_t q;
};

static int pgpSetSigMpiEDDSA(pgpDigAlg pgpsig, int num, const uint8_t *p)
{
struct pgpDigSigEDDSA_s *sig = pgpsig->data;
int mlen = pgpMpiLen(p);
int rc = 1;

if (!sig)
sig = pgpsig->data = xcalloc(1, sizeof(*sig));

switch (num) {
case 0:
if (!gcry_mpi_scan(&sig->r, GCRYMPI_FMT_PGP, p, mlen, NULL))
rc = 0;
break;
case 1:
if (!gcry_mpi_scan(&sig->s, GCRYMPI_FMT_PGP, p, mlen, NULL))
rc = 0;
break;
}
return rc;
}

static int pgpSetKeyMpiEDDSA(pgpDigAlg pgpkey, int num, const uint8_t *p)
{
struct pgpDigKeyEDDSA_s *key = pgpkey->data;
int mlen = pgpMpiLen(p);
int rc = 1;

if (!key)
key = pgpkey->data = xcalloc(1, sizeof(*key));

switch (num) {
case 0:
if (!gcry_mpi_scan(&key->q, GCRYMPI_FMT_PGP, p, mlen, NULL))
rc = 0;
break;
}
return rc;
}

static int
ed25519_zero_extend(gcry_mpi_t x, unsigned char *buf, int bufl)
{
int n = (gcry_mpi_get_nbits(x) + 7) / 8;
if (n == 0 || n > bufl)
return 1;
n = bufl - n;
if (n)
memset(buf, 0, n);
gcry_mpi_print(GCRYMPI_FMT_USG, buf + n, bufl - n, NULL, x);
return 0;
}

static int pgpVerifySigEDDSA(pgpDigAlg pgpkey, pgpDigAlg pgpsig, uint8_t *hash, size_t hashlen, int hash_algo)
{
struct pgpDigKeyEDDSA_s *key = pgpkey->data;
struct pgpDigSigEDDSA_s *sig = pgpsig->data;
gcry_sexp_t sexp_sig = NULL, sexp_data = NULL, sexp_pkey = NULL;
int rc = 1;
unsigned char buf_r[32], buf_s[32];

if (!sig || !key)
return rc;
if (pgpkey->curve != PGPCURVE_ED25519)
return rc;
if (hash_algo != PGPHASHALGO_SHA256)
return rc;
if (ed25519_zero_extend(sig->r, buf_r, 32) || ed25519_zero_extend(sig->s, buf_s, 32))
return rc;
gcry_sexp_build(&sexp_sig, NULL, "(sig-val (eddsa (r %b) (s %b)))", 32, (const char *)buf_r, 32, (const char *)buf_s, 32);
gcry_sexp_build(&sexp_data, NULL, "(data (flags eddsa) (hash-algo sha512) (value %b))", (int)hashlen, (const char *)hash);
gcry_sexp_build(&sexp_pkey, NULL, "(public-key (ecc (curve \"Ed25519\") (flags eddsa) (q %M)))", key->q);
if (sexp_sig && sexp_data && sexp_pkey)
rc = gcry_pk_verify(sexp_sig, sexp_data, sexp_pkey) == 0 ? 0 : 1;
gcry_sexp_release(sexp_sig);
gcry_sexp_release(sexp_data);
gcry_sexp_release(sexp_pkey);
return rc;
}

static void pgpFreeSigEDDSA(pgpDigAlg pgpsig)
{
struct pgpDigSigEDDSA_s *sig = pgpsig->data;
if (sig) {
gcry_mpi_release(sig->r);
gcry_mpi_release(sig->s);
pgpsig->data = _free(sig);
}
}

static void pgpFreeKeyEDDSA(pgpDigAlg pgpkey)
{
struct pgpDigKeyEDDSA_s *key = pgpkey->data;
if (key) {
gcry_mpi_release(key->q);
pgpkey->data = _free(key);
}
}


/****************************** NULL **************************************/

static int pgpSetMpiNULL(pgpDigAlg pgpkey, int num, const uint8_t *p)
Expand All @@ -359,7 +470,24 @@ static int pgpVerifyNULL(pgpDigAlg pgpkey, pgpDigAlg pgpsig,
return 1;
}

pgpDigAlg pgpPubkeyNew(int algo)
static int pgpSupportedCurve(int curve)
{
if (curve == PGPCURVE_ED25519) {
static int supported_ed25519;
if (!supported_ed25519) {
gcry_sexp_t sexp = NULL;
unsigned int nbits;
gcry_sexp_build(&sexp, NULL, "(public-key (ecc (curve \"Ed25519\")))");
nbits = gcry_pk_get_nbits(sexp);
gcry_sexp_release(sexp);
supported_ed25519 = nbits > 0 ? 1 : -1;
}
return supported_ed25519 > 0;
}
return 0;
}

pgpDigAlg pgpPubkeyNew(int algo, int curve)
{
pgpDigAlg ka = xcalloc(1, sizeof(*ka));;

Expand All @@ -374,6 +502,17 @@ pgpDigAlg pgpPubkeyNew(int algo)
ka->free = pgpFreeKeyDSA;
ka->mpis = 4;
break;
case PGPPUBKEYALGO_EDDSA:
if (!pgpSupportedCurve(curve)) {
ka->setmpi = pgpSetMpiNULL;
ka->mpis = -1;
break;
}
ka->setmpi = pgpSetKeyMpiEDDSA;
ka->free = pgpFreeKeyEDDSA;
ka->mpis = 1;
ka->curve = curve;
break;
default:
ka->setmpi = pgpSetMpiNULL;
ka->mpis = -1;
Expand Down Expand Up @@ -402,6 +541,12 @@ pgpDigAlg pgpSignatureNew(int algo)
sa->verify = pgpVerifySigDSA;
sa->mpis = 2;
break;
case PGPPUBKEYALGO_EDDSA:
sa->setmpi = pgpSetSigMpiEDDSA;
sa->free = pgpFreeSigEDDSA;
sa->verify = pgpVerifySigEDDSA;
sa->mpis = 2;
break;
default:
sa->setmpi = pgpSetMpiNULL;
sa->verify = pgpVerifyNULL;
Expand Down
2 changes: 1 addition & 1 deletion rpmio/digest_nss.c
Expand Up @@ -478,7 +478,7 @@ static int pgpVerifyNULL(pgpDigAlg pgpkey, pgpDigAlg pgpsig,
return 1;
}

pgpDigAlg pgpPubkeyNew(int algo)
pgpDigAlg pgpPubkeyNew(int algo, int curve)
{
pgpDigAlg ka = xcalloc(1, sizeof(*ka));;

Expand Down
121 changes: 120 additions & 1 deletion rpmio/digest_openssl.c
Expand Up @@ -766,6 +766,104 @@ static int pgpVerifySigDSA(pgpDigAlg pgpkey, pgpDigAlg pgpsig,
return rc;
}


/****************************** EDDSA ***************************************/

#ifdef EVP_PKEY_ED25519

struct pgpDigKeyEDDSA_s {
EVP_PKEY *evp_pkey; /* Fully constructed key */
unsigned char *q; /* compressed point */
int qlen;
};

static int constructEDDSASigningKey(struct pgpDigKeyEDDSA_s *key, int curve)
{
if (key->evp_pkey)
return 1; /* We've already constructed it, so just reuse it */
if (curve == PGPCURVE_ED25519)
key->evp_pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, key->q, key->qlen);
return key->evp_pkey ? 1 : 0;
}

static int pgpSetKeyMpiEDDSA(pgpDigAlg pgpkey, int num, const uint8_t *p)
{
size_t mlen = pgpMpiLen(p) - 2;
struct pgpDigKeyEDDSA_s *key = pgpkey->data;
int rc = 1;

if (!key)
key = pgpkey->data = xcalloc(1, sizeof(*key));
if (num == 0 && !key->q && mlen > 1 && p[2] == 0x40) {
key->qlen = mlen - 1;
key->q = xmalloc(key->qlen);
memcpy(key->q, p + 3, key->qlen),
rc = 0;
}
return rc;
}

static void pgpFreeKeyEDDSA(pgpDigAlg pgpkey)
{
struct pgpDigKeyEDDSA_s *key = pgpkey->data;
if (key) {
if (key->q)
free(key->q);
if (key->evp_pkey)
EVP_PKEY_free(key->evp_pkey);
free(key);
}
}

struct pgpDigSigEDDSA_s {
unsigned char sig[32 + 32];
};

static int pgpSetSigMpiEDDSA(pgpDigAlg pgpsig, int num, const uint8_t *p)
{
struct pgpDigSigEDDSA_s *sig = pgpsig->data;
int mlen = pgpMpiLen(p) - 2;

if (!sig)
sig = pgpsig->data = xcalloc(1, sizeof(*sig));
if (!mlen || mlen > 32 || (num != 0 && num != 1))
return 1;
memcpy(sig->sig + 32 * num + 32 - mlen, p + 2, mlen);
return 0;
}

static void pgpFreeSigEDDSA(pgpDigAlg pgpsig)
{
struct pgpDigSigEDDSA_s *sig = pgpsig->data;
if (sig) {
free(pgpsig->data);
}
}

static int pgpVerifySigEDDSA(pgpDigAlg pgpkey, pgpDigAlg pgpsig,
uint8_t *hash, size_t hashlen, int hash_algo)
{
int rc = 1; /* assume failure */
struct pgpDigSigEDDSA_s *sig = pgpsig->data;
struct pgpDigKeyEDDSA_s *key = pgpkey->data;
EVP_MD_CTX *md_ctx = NULL;

if (!constructEDDSASigningKey(key, pgpkey->curve))
goto done;
md_ctx = EVP_MD_CTX_new();
if (EVP_DigestVerifyInit(md_ctx, NULL, EVP_md_null(), NULL, key->evp_pkey) != 1)
goto done;
if (EVP_DigestVerify(md_ctx, sig->sig, 64, hash, hashlen) == 1)
rc = 0; /* Success */
done:
if (md_ctx)
EVP_MD_CTX_free(md_ctx);
return rc;
}

#endif


/****************************** NULL **************************************/

static int pgpSetMpiNULL(pgpDigAlg pgpkey, int num, const uint8_t *p)
Expand All @@ -780,7 +878,7 @@ static int pgpVerifyNULL(pgpDigAlg pgpkey, pgpDigAlg pgpsig,
}

/****************************** PGP **************************************/
pgpDigAlg pgpPubkeyNew(int algo)
pgpDigAlg pgpPubkeyNew(int algo, int curve)
{
pgpDigAlg ka = xcalloc(1, sizeof(*ka));;

Expand All @@ -795,6 +893,19 @@ pgpDigAlg pgpPubkeyNew(int algo)
ka->free = pgpFreeKeyDSA;
ka->mpis = 4;
break;
#ifdef EVP_PKEY_ED25519
case PGPPUBKEYALGO_EDDSA:
if (curve != PGPCURVE_ED25519) {
ka->setmpi = pgpSetMpiNULL; /* unsupported curve */
ka->mpis = -1;
break;
}
ka->setmpi = pgpSetKeyMpiEDDSA;
ka->free = pgpFreeKeyEDDSA;
ka->mpis = 1;
ka->curve = curve;
break;
#endif
default:
ka->setmpi = pgpSetMpiNULL;
ka->mpis = -1;
Expand Down Expand Up @@ -823,6 +934,14 @@ pgpDigAlg pgpSignatureNew(int algo)
sa->verify = pgpVerifySigDSA;
sa->mpis = 2;
break;
#ifdef EVP_PKEY_ED25519
case PGPPUBKEYALGO_EDDSA:
sa->setmpi = pgpSetSigMpiEDDSA;
sa->free = pgpFreeSigEDDSA;
sa->verify = pgpVerifySigEDDSA;
sa->mpis = 2;
break;
#endif
default:
sa->setmpi = pgpSetMpiNULL;
sa->verify = pgpVerifyNULL;
Expand Down