aboutsummaryrefslogtreecommitdiffstats
path: root/common/sexputil.c
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2020-05-19 12:28:40 +0000
committerWerner Koch <[email protected]>2020-05-19 12:28:48 +0000
commit3cd9dac7e0976643c6e4b6537cf363b2b12d422f (patch)
treee0e3d85f3aa20d2ac141d70c1808fa600844f4fa /common/sexputil.c
parentsm: Support creation of EdDSA certificates. (diff)
downloadgnupg-3cd9dac7e0976643c6e4b6537cf363b2b12d422f.tar.gz
gnupg-3cd9dac7e0976643c6e4b6537cf363b2b12d422f.zip
common: New function to extract Q from an ECC key.
* common/sexputil.c (get_ecc_q_from_canon_sexp): New. Signed-off-by: Werner Koch <[email protected]>
Diffstat (limited to 'common/sexputil.c')
-rw-r--r--common/sexputil.c90
1 files changed, 89 insertions, 1 deletions
diff --git a/common/sexputil.c b/common/sexputil.c
index 7a67f2b7c..b007b71f6 100644
--- a/common/sexputil.c
+++ b/common/sexputil.c
@@ -199,7 +199,7 @@ make_canon_sexp_pad (gcry_sexp_t sexp, int secure,
}
/* Return the so called "keygrip" which is the SHA-1 hash of the
- public key parameters expressed in a way depended on the algorithm.
+ public key parameters expressed in a way dependend on the algorithm.
KEY is expected to be an canonical encoded S-expression with a
public or private key. KEYLEN is the length of that buffer.
@@ -512,6 +512,94 @@ get_rsa_pk_from_canon_sexp (const unsigned char *keydata, size_t keydatalen,
}
+/* Return the public key parameter Q of a public RSA or ECC key
+ * expressed as an canonical encoded S-expression. */
+gpg_error_t
+get_ecc_q_from_canon_sexp (const unsigned char *keydata, size_t keydatalen,
+ unsigned char const **r_q, size_t *r_qlen)
+{
+ gpg_error_t err;
+ const unsigned char *buf, *tok;
+ size_t buflen, toklen;
+ int depth, last_depth1, last_depth2;
+ const unsigned char *ecc_q = NULL;
+ size_t ecc_q_len;
+
+ *r_q = NULL;
+ *r_qlen = 0;
+
+ buf = keydata;
+ buflen = keydatalen;
+ depth = 0;
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if (!tok || toklen != 10 || memcmp ("public-key", tok, toklen))
+ return gpg_error (GPG_ERR_BAD_PUBKEY);
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if (tok && toklen == 3 && !memcmp ("ecc", tok, toklen))
+ ;
+ else if (tok && toklen == 5 && (!memcmp ("ecdsa", tok, toklen)
+ || !memcmp ("eddsa", tok, toklen)))
+ ;
+ else
+ return gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
+
+ last_depth1 = depth;
+ while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
+ && depth && depth >= last_depth1)
+ {
+ if (tok)
+ return gpg_error (GPG_ERR_UNKNOWN_SEXP);
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if (tok && toklen == 1)
+ {
+ const unsigned char **mpi;
+ size_t *mpi_len;
+
+ switch (*tok)
+ {
+ case 'q': mpi = &ecc_q; mpi_len = &ecc_q_len; break;
+ default: mpi = NULL; mpi_len = NULL; break;
+ }
+ if (mpi && *mpi)
+ return gpg_error (GPG_ERR_DUP_VALUE);
+
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if (tok && mpi)
+ {
+ *mpi = tok;
+ *mpi_len = toklen;
+ }
+ }
+
+ /* Skip to the end of the list. */
+ last_depth2 = depth;
+ while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
+ && depth && depth >= last_depth2)
+ ;
+ if (err)
+ return err;
+ }
+
+ if (err)
+ return err;
+
+ if (!ecc_q || !ecc_q_len)
+ return gpg_error (GPG_ERR_BAD_PUBKEY);
+
+ *r_q = ecc_q;
+ *r_qlen = ecc_q_len;
+ return 0;
+}
+
+
/* Return the algo of a public KEY of SEXP. */
int
get_pk_algo_from_key (gcry_sexp_t key)