diff options
author | Werner Koch <[email protected]> | 2020-05-19 12:28:40 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2020-05-19 12:28:48 +0000 |
commit | 3cd9dac7e0976643c6e4b6537cf363b2b12d422f (patch) | |
tree | e0e3d85f3aa20d2ac141d70c1808fa600844f4fa /common/sexputil.c | |
parent | sm: Support creation of EdDSA certificates. (diff) | |
download | gnupg-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.c | 90 |
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) |