diff options
author | Werner Koch <wk@gnupg.org> | 2013-10-16 16:20:56 +0200 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2013-10-16 16:20:56 +0200 |
commit | a329b6abf00c990faf1986f9fbad7b4d71c13bcb (patch) | |
tree | 52b1f995cbc863404fb8a01005f3d17c29706655 | |
parent | 45aa6131e93fac89d46733b3436d960f35fb99b2 (diff) | |
download | libgcrypt-a329b6abf00c990faf1986f9fbad7b4d71c13bcb.tar.gz |
sexp: Add function gcry_sexp_extract_param.
* src/gcrypt.h.in (_GCRY_GCC_ATTR_SENTINEL): New.
(gcry_sexp_extract_param): New.
* src/visibility.c (gcry_sexp_extract_param): New.
* src/visibility.h (gcry_sexp_extract_param): Add hack to detect
internal use.
* cipher/pubkey-util.c (_gcry_pk_util_extract_mpis): Move and split
into ...
* src/sexp.c (_gcry_sexp_vextract_param)
(_gcry_sexp_extract_param): this. Change all callers. Add support for buffer
descriptors and a path option/
* tests/tsexp.c (die, hex2buffer, hex2mpi, hex2mpiopa): New.
(cmp_mpihex, cmp_bufhex): New.
(check_extract_param): New.
Signed-off-by: Werner Koch <wk@gnupg.org>
-rw-r--r-- | NEWS | 5 | ||||
-rw-r--r-- | cipher/dsa.c | 16 | ||||
-rw-r--r-- | cipher/ecc-curves.c | 6 | ||||
-rw-r--r-- | cipher/ecc-misc.c | 1 | ||||
-rw-r--r-- | cipher/ecc.c | 38 | ||||
-rw-r--r-- | cipher/elgamal.c | 27 | ||||
-rw-r--r-- | cipher/pubkey-internal.h | 3 | ||||
-rw-r--r-- | cipher/pubkey-util.c | 113 | ||||
-rw-r--r-- | cipher/rsa.c | 26 | ||||
-rw-r--r-- | doc/gcrypt.texi | 60 | ||||
-rw-r--r-- | src/g10lib.h | 13 | ||||
-rw-r--r-- | src/gcrypt.h.in | 15 | ||||
-rw-r--r-- | src/libgcrypt.def | 3 | ||||
-rw-r--r-- | src/libgcrypt.vers | 2 | ||||
-rw-r--r-- | src/sexp.c | 235 | ||||
-rw-r--r-- | src/visibility.c | 15 | ||||
-rw-r--r-- | src/visibility.h | 13 | ||||
-rw-r--r-- | tests/tsexp.c | 516 |
18 files changed, 920 insertions, 187 deletions
@@ -35,13 +35,13 @@ Noteworthy changes in version 1.6.0 (unreleased) * Added a scatter gather hash convenience function. - * Added several MPI helper functions. + * Added several MPI amd SEXP helper functions. * Added support for negative numbers to gcry_mpi_print, gcry_mpi_aprint and gcry_mpi_scan. * The algorithm ids GCRY_PK_ECDSA and GCRY_PK_ECDH are now - deprecated. Use GCRY_PK_ECC instead. + deprecated. Use GCRY_PK_ECC if you need an algorithm id. * Interface changes relative to the 1.5.0 release: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -108,6 +108,7 @@ Noteworthy changes in version 1.6.0 (unreleased) GCRYCTL_DISABLE_PRIV_DROP NEW. GCRY_CIPHER_SALSA20 NEW. gcry_sexp_nth_buffer NEW. + gcry_sexp_extract_param NEW. GCRY_CIPHER_SALSA20R12 NEW. GCRY_CIPHER_GOST28147 NEW. GCRY_MD_GOSTR3411_94 NEW. diff --git a/cipher/dsa.c b/cipher/dsa.c index e43bdf44..45ad97a6 100644 --- a/cipher/dsa.c +++ b/cipher/dsa.c @@ -956,9 +956,9 @@ dsa_check_secret_key (gcry_sexp_t keyparms) gcry_err_code_t rc; DSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL}; - rc = _gcry_pk_util_extract_mpis (keyparms, "pqgyx", - &sk.p, &sk.q, &sk.g, &sk.y, &sk.x, - NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "pqgyx", + &sk.p, &sk.q, &sk.g, &sk.y, &sk.x, + NULL); if (rc) goto leave; @@ -998,8 +998,8 @@ dsa_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) log_mpidump ("dsa_sign data", data); /* Extract the key. */ - rc = _gcry_pk_util_extract_mpis (keyparms, "pqgyx", - &sk.p, &sk.q, &sk.g, &sk.y, &sk.x, NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "pqgyx", + &sk.p, &sk.q, &sk.g, &sk.y, &sk.x, NULL); if (rc) goto leave; if (DBG_CIPHER) @@ -1065,7 +1065,7 @@ dsa_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms) rc = _gcry_pk_util_preparse_sigval (s_sig, dsa_names, &l1, NULL); if (rc) goto leave; - rc = _gcry_pk_util_extract_mpis (l1, "rs", &sig_r, &sig_s, NULL); + rc = _gcry_sexp_extract_param (l1, NULL, "rs", &sig_r, &sig_s, NULL); if (rc) goto leave; if (DBG_CIPHER) @@ -1075,8 +1075,8 @@ dsa_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms) } /* Extract the key. */ - rc = _gcry_pk_util_extract_mpis (s_keyparms, "pqgy", - &pk.p, &pk.q, &pk.g, &pk.y, NULL); + rc = _gcry_sexp_extract_param (s_keyparms, NULL, "pqgy", + &pk.p, &pk.q, &pk.g, &pk.y, NULL); if (rc) goto leave; if (DBG_CIPHER) diff --git a/cipher/ecc-curves.c b/cipher/ecc-curves.c index 53433a2c..2cdb9b4d 100644 --- a/cipher/ecc-curves.c +++ b/cipher/ecc-curves.c @@ -436,9 +436,9 @@ _gcry_ecc_get_curve (gcry_sexp_t keyparms, int iterator, unsigned int *r_nbits) /* * Extract the curve parameters.. */ - if (_gcry_pk_util_extract_mpis (keyparms, "-pabgn", - &E.p, &E.a, &E.b, &mpi_g, &E.n, - NULL)) + if (_gcry_sexp_extract_param (keyparms, NULL, "-pabgn", + &E.p, &E.a, &E.b, &mpi_g, &E.n, + NULL)) goto leave; if (mpi_g) { diff --git a/cipher/ecc-misc.c b/cipher/ecc-misc.c index d89971f0..fa0bded5 100644 --- a/cipher/ecc-misc.c +++ b/cipher/ecc-misc.c @@ -55,6 +55,7 @@ _gcry_ecc_curve_copy (elliptic_curve_t E) R.model = E.model; R.dialect = E.dialect; + R.name = E.name; R.p = mpi_copy (E.p); R.a = mpi_copy (E.a); R.b = mpi_copy (E.b); diff --git a/cipher/ecc.c b/cipher/ecc.c index 3b75feac..1323d00a 100644 --- a/cipher/ecc.c +++ b/cipher/ecc.c @@ -1435,9 +1435,9 @@ ecc_check_secret_key (gcry_sexp_t keyparms) /* * Extract the key. */ - rc = _gcry_pk_util_extract_mpis (keyparms, "-p?a?b?g?n?/q?+d", - &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n, - &mpi_q, &sk.d, NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "-p?a?b?g?n?/q?+d", + &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n, + &mpi_q, &sk.d, NULL); if (rc) goto leave; if (mpi_g) @@ -1552,9 +1552,9 @@ ecc_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) /* * Extract the key. */ - rc = _gcry_pk_util_extract_mpis (keyparms, "-p?a?b?g?n?/q?+d", - &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n, - &mpi_q, &sk.d, NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "-p?a?b?g?n?/q?+d", + &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n, + &mpi_q, &sk.d, NULL); if (rc) goto leave; if (mpi_g) @@ -1686,9 +1686,9 @@ ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms) rc = _gcry_pk_util_preparse_sigval (s_sig, ecc_names, &l1, &sigflags); if (rc) goto leave; - rc = _gcry_pk_util_extract_mpis (l1, - (sigflags & PUBKEY_FLAG_EDDSA)? "/rs":"rs", - &sig_r, &sig_s, NULL); + rc = _gcry_sexp_extract_param (l1, NULL, + (sigflags & PUBKEY_FLAG_EDDSA)? "/rs":"rs", + &sig_r, &sig_s, NULL); if (rc) goto leave; if (DBG_CIPHER) @@ -1706,9 +1706,9 @@ ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms) /* * Extract the key. */ - rc = _gcry_pk_util_extract_mpis (s_keyparms, "-p?a?b?g?n?/q?", - &pk.E.p, &pk.E.a, &pk.E.b, &mpi_g, &pk.E.n, - &mpi_q, NULL); + rc = _gcry_sexp_extract_param (s_keyparms, NULL, "-p?a?b?g?n?/q?", + &pk.E.p, &pk.E.a, &pk.E.b, &mpi_g, &pk.E.n, + &mpi_q, NULL); if (rc) goto leave; if (mpi_g) @@ -1890,9 +1890,9 @@ ecc_encrypt_raw (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms) /* * Extract the key. */ - rc = _gcry_pk_util_extract_mpis (keyparms, "-p?a?b?g?n?+q", - &pk.E.p, &pk.E.a, &pk.E.b, &mpi_g, &pk.E.n, - &mpi_q, NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "-p?a?b?g?n?+q", + &pk.E.p, &pk.E.a, &pk.E.b, &mpi_g, &pk.E.n, + &mpi_q, NULL); if (rc) goto leave; if (mpi_g) @@ -2044,7 +2044,7 @@ ecc_decrypt_raw (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms) rc = _gcry_pk_util_preparse_encval (s_data, ecc_names, &l1, &ctx); if (rc) goto leave; - rc = _gcry_pk_util_extract_mpis (l1, "e", &data_e, NULL); + rc = _gcry_sexp_extract_param (l1, NULL, "e", &data_e, NULL); if (rc) goto leave; if (DBG_CIPHER) @@ -2058,9 +2058,9 @@ ecc_decrypt_raw (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms) /* * Extract the key. */ - rc = _gcry_pk_util_extract_mpis (keyparms, "-p?a?b?g?n?+d", - &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n, - &sk.d, NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "-p?a?b?g?n?+d", + &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n, + &sk.d, NULL); if (rc) goto leave; if (mpi_g) diff --git a/cipher/elgamal.c b/cipher/elgamal.c index 691e122b..432ba6fd 100644 --- a/cipher/elgamal.c +++ b/cipher/elgamal.c @@ -735,9 +735,9 @@ elg_check_secret_key (gcry_sexp_t keyparms) gcry_err_code_t rc; ELG_secret_key sk = {NULL, NULL, NULL, NULL}; - rc = _gcry_pk_util_extract_mpis (keyparms, "pgyx", - &sk.p, &sk.g, &sk.y, &sk.x, - NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "pgyx", + &sk.p, &sk.g, &sk.y, &sk.x, + NULL); if (rc) goto leave; @@ -781,7 +781,8 @@ elg_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms) } /* Extract the key. */ - rc = _gcry_pk_util_extract_mpis (keyparms, "pgy", &pk.p, &pk.g, &pk.y, NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "pgy", + &pk.p, &pk.g, &pk.y, NULL); if (rc) goto leave; if (DBG_CIPHER) @@ -831,7 +832,7 @@ elg_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms) rc = _gcry_pk_util_preparse_encval (s_data, elg_names, &l1, &ctx); if (rc) goto leave; - rc = _gcry_pk_util_extract_mpis (l1, "ab", &data_a, &data_b, NULL); + rc = _gcry_sexp_extract_param (l1, NULL, "ab", &data_a, &data_b, NULL); if (rc) goto leave; if (DBG_CIPHER) @@ -846,9 +847,9 @@ elg_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms) } /* Extract the key. */ - rc = _gcry_pk_util_extract_mpis (keyparms, "pgyx", - &sk.p, &sk.g, &sk.y, &sk.x, - NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "pgyx", + &sk.p, &sk.g, &sk.y, &sk.x, + NULL); if (rc) goto leave; if (DBG_CIPHER) @@ -940,8 +941,8 @@ elg_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) } /* Extract the key. */ - rc = _gcry_pk_util_extract_mpis (keyparms, "pgyx", - &sk.p, &sk.g, &sk.y, &sk.x, NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "pgyx", + &sk.p, &sk.g, &sk.y, &sk.x, NULL); if (rc) goto leave; if (DBG_CIPHER) @@ -1008,7 +1009,7 @@ elg_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms) rc = _gcry_pk_util_preparse_sigval (s_sig, elg_names, &l1, NULL); if (rc) goto leave; - rc = _gcry_pk_util_extract_mpis (l1, "rs", &sig_r, &sig_s, NULL); + rc = _gcry_sexp_extract_param (l1, NULL, "rs", &sig_r, &sig_s, NULL); if (rc) goto leave; if (DBG_CIPHER) @@ -1018,8 +1019,8 @@ elg_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms) } /* Extract the key. */ - rc = _gcry_pk_util_extract_mpis (s_keyparms, "pgy", - &pk.p, &pk.g, &pk.y, NULL); + rc = _gcry_sexp_extract_param (s_keyparms, NULL, "pgy", + &pk.p, &pk.g, &pk.y, NULL); if (rc) goto leave; if (DBG_CIPHER) diff --git a/cipher/pubkey-internal.h b/cipher/pubkey-internal.h index cb2721d1..db1399d2 100644 --- a/cipher/pubkey-internal.h +++ b/cipher/pubkey-internal.h @@ -28,9 +28,6 @@ gpg_err_code_t _gcry_pk_util_get_nbits (gcry_sexp_t list, unsigned int *r_nbits); gpg_err_code_t _gcry_pk_util_get_rsa_use_e (gcry_sexp_t list, unsigned long *r_e); -gpg_err_code_t _gcry_pk_util_extract_mpis (gcry_sexp_t sexp, - const char *list, ...) - GCC_ATTR_SENTINEL(0); gpg_err_code_t _gcry_pk_util_preparse_sigval (gcry_sexp_t s_sig, const char **algo_names, gcry_sexp_t *r_parms, diff --git a/cipher/pubkey-util.c b/cipher/pubkey-util.c index caf715eb..0b90054f 100644 --- a/cipher/pubkey-util.c +++ b/cipher/pubkey-util.c @@ -273,119 +273,6 @@ _gcry_pk_util_get_rsa_use_e (gcry_sexp_t list, unsigned long *r_e) } -/* Extract MPIs from an s-expression using a list of one letter - * parameters. The names of these parameters are given by the string - * LIST. Some special characters may be given to control the - * conversion: - * - * + :: Switch to unsigned integer format (default). - * - :: Switch to standard signed format. - * / :: Switch to opaque format. - * ? :: The previous parameter is optional. - * - * For each parameter name a pointer to an MPI variable is expected - * and finally a NULL is expected. Example: - * - * _gcry_pk_util_extract_mpis (key, "n/x+ed", &mpi_n, &mpi_x, &mpi_e, NULL) - * - * This stores the parameter "N" from KEY as an unsigned MPI into - * MPI_N, the parameter "X" as an opaque MPI into MPI_X, and the - * parameter "E" again as an unsigned MPI into MPI_E. - * - * The function returns NULL on success. On error an error code is - * returned and the passed MPIs are either unchanged or set to NULL. - */ -gpg_err_code_t -_gcry_pk_util_extract_mpis (gcry_sexp_t sexp, const char *list, ...) -{ - va_list arg_ptr; - const char *s; - gcry_mpi_t *array[10]; - int idx; - gcry_sexp_t l1; - enum gcry_mpi_format mpifmt = GCRYMPI_FMT_USG; - - /* First copy all the args into an array. This is required so that - we are able to release already allocated MPIs if later an error - was found. */ - va_start (arg_ptr, list) ; - for (s=list, idx=0; *s && idx < DIM (array); s++) - { - if (*s == '+' || *s == '-' || *s == '/' || *s == '?') - ; - else - { - array[idx] = va_arg (arg_ptr, gcry_mpi_t *); - if (!array[idx]) - { - va_end (arg_ptr); - return GPG_ERR_INTERNAL; /* NULL pointer given. */ - } - idx++; - } - } - if (*s) - { - va_end (arg_ptr); - return GPG_ERR_INTERNAL; /* Too many list elements. */ - } - if (va_arg (arg_ptr, gcry_mpi_t *)) - { - va_end (arg_ptr); - return GPG_ERR_INTERNAL; /* Not enough list elemends. */ - } - va_end (arg_ptr); - - /* Now extract all parameters. */ - for (s=list, idx=0; *s; s++) - { - if (*s == '+') - mpifmt = GCRYMPI_FMT_USG; - else if (*s == '-') - mpifmt = GCRYMPI_FMT_STD; - else if (*s == '/') - mpifmt = GCRYMPI_FMT_HEX; /* Used to indicate opaque. */ - else if (*s == '?') - ; /* Only used via lookahead. */ - else - { - l1 = gcry_sexp_find_token (sexp, s, 1); - if (!l1 && s[1] == '?') - *array[idx] = NULL; /* Optional element not found. */ - else if (!l1) - { - while (idx--) - { - gcry_mpi_release (*array[idx]); - *array[idx] = NULL; - } - return GPG_ERR_NO_OBJ; /* List element not found. */ - } - else - { - if (mpifmt == GCRYMPI_FMT_HEX) - *array[idx] = _gcry_sexp_nth_opaque_mpi (l1, 1); - else - *array[idx] = gcry_sexp_nth_mpi (l1, 1, mpifmt); - gcry_sexp_release (l1); - if (!*array[idx]) - { - while (idx--) - { - gcry_mpi_release (*array[idx]); - *array[idx] = NULL; - } - return GPG_ERR_INV_OBJ; /* Conversion failed. */ - } - } - idx++; - } - } - - return 0; -} - - /* Parse a "sig-val" s-expression and store the inner parameter list at R_PARMS. ALGO_NAMES is used to verify that the algorithm in "sig-val" is valid. Returns 0 on success and stores a new list at diff --git a/cipher/rsa.c b/cipher/rsa.c index d4d2a0ab..fed52a1f 100644 --- a/cipher/rsa.c +++ b/cipher/rsa.c @@ -855,9 +855,9 @@ rsa_check_secret_key (gcry_sexp_t keyparms) RSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL, NULL}; /* To check the key we need the optional parameters. */ - rc = _gcry_pk_util_extract_mpis (keyparms, "nedpqu", - &sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u, - NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "nedpqu", + &sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u, + NULL); if (rc) goto leave; @@ -902,7 +902,7 @@ rsa_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms) } /* Extract the key. */ - rc = _gcry_pk_util_extract_mpis (keyparms, "ne", &pk.n, &pk.e, NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "ne", &pk.n, &pk.e, NULL); if (rc) goto leave; if (DBG_CIPHER) @@ -969,7 +969,7 @@ rsa_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms) rc = _gcry_pk_util_preparse_encval (s_data, rsa_names, &l1, &ctx); if (rc) goto leave; - rc = _gcry_pk_util_extract_mpis (l1, "a", &data, NULL); + rc = _gcry_sexp_extract_param (l1, NULL, "a", &data, NULL); if (rc) goto leave; if (DBG_CIPHER) @@ -981,9 +981,9 @@ rsa_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms) } /* Extract the key. */ - rc = _gcry_pk_util_extract_mpis (keyparms, "nedp?q?u?", - &sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u, - NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "nedp?q?u?", + &sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u, + NULL); if (rc) goto leave; if (DBG_CIPHER) @@ -1125,9 +1125,9 @@ rsa_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) } /* Extract the key. */ - rc = _gcry_pk_util_extract_mpis (keyparms, "nedp?q?u?", - &sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u, - NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "nedp?q?u?", + &sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u, + NULL); if (rc) goto leave; if (DBG_CIPHER) @@ -1213,14 +1213,14 @@ rsa_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) rc = _gcry_pk_util_preparse_sigval (s_sig, rsa_names, &l1, NULL); if (rc) goto leave; - rc = _gcry_pk_util_extract_mpis (l1, "s", &sig, NULL); + rc = _gcry_sexp_extract_param (l1, NULL, "s", &sig, NULL); if (rc) goto leave; if (DBG_CIPHER) log_printmpi ("rsa_verify sig", sig); /* Extract the key. */ - rc = _gcry_pk_util_extract_mpis (keyparms, "ne", &pk.n, &pk.e, NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "ne", &pk.n, &pk.e, NULL); if (rc) goto leave; if (DBG_CIPHER) diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi index 79d4d740..473c484c 100644 --- a/doc/gcrypt.texi +++ b/doc/gcrypt.texi @@ -3748,6 +3748,66 @@ this function to parse results of a public key function, you most likely want to use @code{GCRYMPI_FMT_USG}. @end deftypefun +@deftypefun gpg_error_t gcry_sexp_extract_param ( @ + @w{gcry_sexp_t @var{sexp}}, @ + @w{const char *@var{path}}, @ + @w{const char *@var{list}}, ...) + +Extract parameters from an S-expression using a list of single letter +parameter names. The names of these parameters are specified in +LIST. Some special characters may be given to control the +conversion: + +@table @samp +@item + +Switch to unsigned integer format (GCRYMPI_FMT_USG). This is the +default mode. +@item - +Switch to standard signed format (GCRYMPI_FMT_STD). +@item / +Switch to opaque MPI format. The resulting MPIs may not be used for +computations; see @code{gcry_mpi_get_opaque} for details. +@item & +Switch to buffer descriptor mode. See below for details. +@item ? +If immediately following a parameter letter, that parameter is +considered optional. +@end table + +Unless in buffer descriptor mode for each parameter name a pointer to +an @code{gcry_mpi_t} variable is expected finally followed by a @code{NULL}. +For example +@example + _gcry_sexp_extract_param (key, NULL, "n/x+ed", + &mpi_n, &mpi_x, &mpi_e, NULL) +@end example + +stores the parameter 'n' from @var{key} as an unsigned MPI into +@var{mpi_n}, the parameter 'x' as an opaque MPI into @var{mpi_x}, and +the parameter 'e' again as an unsigned MPI into @var{mpi_e}. + +@var{path} is an optional string used to locate a token. The +exclamation mark separated tokens are used via +@code{gcry_sexp_find_token} to find a start point inside the +S-expression. + +In buffer descriptor mode a pointer to a @code{gcry_buffer_t} +descriptor is expected instead of a pointer to an MPI. The caller may +use two different operation modes here: If the @var{data} field of the +provided descriptor is @code{NULL}, the function allocates a new +buffer and stores it at @var{data}; the other fields are set +accordingly with @var{off} set to 0. If @var{data} is not +@code{NULL}, the function assumes that the @var{data}, @var{size}, and +@var{off} fields specify a buffer where to but the value of the +respective parameter; on return the @var{len} field receives the +number of bytes copied to that buffer; in case the buffer is too +small, the function immediately returns with an error code (and +@var{len} is set to 0). + +The function returns NULL on success. On error an error code is +returned and the passed MPIs are either unchanged or set to NULL. +@end deftypefun + @c ********************************************************** @c ******************* MPIs ******** *********************** diff --git a/src/g10lib.h b/src/g10lib.h index c1ba2f79..3b094487 100644 --- a/src/g10lib.h +++ b/src/g10lib.h @@ -75,13 +75,6 @@ #define GCC_ATTR_UNUSED #endif -#if __GNUC__ >= 4 -# define GCC_ATTR_SENTINEL(a) __attribute__ ((sentinel(a))) -#else -# define GCC_ATTR_SENTINEL(a) -#endif - - /* Gettext macros. */ #define _(a) _gcry_gettext(a) @@ -382,6 +375,12 @@ gcry_err_code_t _gcry_sexp_vbuild (gcry_sexp_t *retsexp, size_t *erroff, const char *format, va_list arg_ptr); gcry_mpi_t _gcry_sexp_nth_opaque_mpi (gcry_sexp_t list, int number); char *_gcry_sexp_nth_string (const gcry_sexp_t list, int number); +gpg_err_code_t _gcry_sexp_vextract_param (gcry_sexp_t sexp, const char *path, + const char *list, va_list arg_ptr); +gpg_err_code_t _gcry_sexp_extract_param (gcry_sexp_t sexp, + const char *path, + const char *list, + ...) _GCRY_GCC_ATTR_SENTINEL(0); /*-- fips.c --*/ diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in index 8646f43d..64cc0e4e 100644 --- a/src/gcrypt.h.in +++ b/src/gcrypt.h.in @@ -102,6 +102,10 @@ extern "C" { #define _GCRY_GCC_ATTR_PRINTF(f,a) __attribute__ ((format (printf,f,a))) +#if _GCRT_GCC_VERSION >= 40000 +#define _GCRY_GCC_ATTR_SENTINEL(a) __attribute__ ((sentinel(a))) +#endif + #endif /*__GNUC__*/ #ifndef _GCRY_GCC_ATTR_DEPRECATED @@ -114,7 +118,10 @@ extern "C" { #define _GCRY_GCC_ATTR_MALLOC #endif #ifndef _GCRY_GCC_ATTR_PRINTF -#define _GCRY_GCC_ATTR_PRINTF +#define _GCRY_GCC_ATTR_PRINTF(f,a) +#endif +#ifndef _GCRY_GCC_ATTR_SENTINEL +#define _GCRY_GCC_ATTR_SENTINEL(a) #endif /* Make up an attribute to mark functions and types as deprecated but @@ -459,6 +466,12 @@ char *gcry_sexp_nth_string (gcry_sexp_t list, int number); value can't be converted to an MPI, `NULL' is returned. */ gcry_mpi_t gcry_sexp_nth_mpi (gcry_sexp_t list, int number, int mpifmt); +/* Convenience fucntion to extract parameters from an S-expression + * using a list of single letter parameters. */ +gpg_error_t gcry_sexp_extract_param (gcry_sexp_t sexp, + const char *path, + const char *list, + ...) _GCRY_GCC_ATTR_SENTINEL(0); /******************************************* diff --git a/src/libgcrypt.def b/src/libgcrypt.def index 7efb3b96..ec0c1e3e 100644 --- a/src/libgcrypt.def +++ b/src/libgcrypt.def @@ -253,5 +253,8 @@ EXPORTS gcry_log_debugpnt @223 gcry_log_debugsxp @224 + gcry_sexp_extract_param @225 + + ;; end of file with public symbols for Windows. diff --git a/src/libgcrypt.vers b/src/libgcrypt.vers index b1669fde..be72aad5 100644 --- a/src/libgcrypt.vers +++ b/src/libgcrypt.vers @@ -76,7 +76,7 @@ GCRYPT_1.6 { gcry_sexp_new; gcry_sexp_nth; gcry_sexp_nth_buffer; gcry_sexp_nth_data; gcry_sexp_nth_mpi; gcry_sexp_prepend; gcry_sexp_release; gcry_sexp_sprint; gcry_sexp_sscan; gcry_sexp_vlist; - gcry_sexp_nth_string; + gcry_sexp_nth_string; gcry_sexp_extract_param; gcry_mpi_is_neg; gcry_mpi_neg; gcry_mpi_abs; gcry_mpi_add; gcry_mpi_add_ui; gcry_mpi_addm; gcry_mpi_aprint; @@ -2117,3 +2117,238 @@ gcry_sexp_canon_len (const unsigned char *buffer, size_t length, } } } + + +/* Extract MPIs from an s-expression using a list of one letter + * parameters. The names of these parameters are given by the string + * LIST. Some special characters may be given to control the + * conversion: + * + * + :: Switch to unsigned integer format (default). + * - :: Switch to standard signed format. + * / :: Switch to opaque format. + * & :: Switch to buffer descriptor mode - see below. + * ? :: The previous parameter is optional. + * + * Unless in gcry_buffer_t mode for each parameter name a pointer to + * an MPI variable is expected and finally a NULL is expected. + * Example: + * + * _gcry_sexp_extract_param (key, NULL, "n/x+ed", + * &mpi_n, &mpi_x, &mpi_e, NULL) + * + * This stores the parameter "N" from KEY as an unsigned MPI into + * MPI_N, the parameter "X" as an opaque MPI into MPI_X, and the + * parameter "E" again as an unsigned MPI into MPI_E. + * + * If in buffer descriptor mode a pointer to gcry_buffer_t descriptor + * is expected instead of a pointer to an MPI. The caller may use two + * different operation modes: If the DATA field of the provided buffer + * descriptor is NULL, the function allocates a new buffer and stores + * it at DATA; the other fields are set accordingly with OFF being 0. + * If DATA is not NULL, the function assumes that DATA, SIZE, and OFF + * describe a buffer where to but the data; on return the LEN field + * receives the number of bytes copied to that buffer; if the buffer + * is too small, the function immediately returns with an error code + * (and LEN set to 0). + * + * PATH is an optional string used to locate a token. The exclamation + * mark separated tokens are used to via gcry_sexp_find_token to find + * a start point inside SEXP. + * + * The function returns NULL on success. On error an error code is + * returned and the passed MPIs are either unchanged or set to NULL. + */ +gpg_err_code_t +_gcry_sexp_vextract_param (gcry_sexp_t sexp, const char *path, + const char *list, va_list arg_ptr) +{ + gpg_err_code_t rc; + const char *s; + gcry_mpi_t *array[20]; + char arrayisdesc[20]; + int idx; + gcry_sexp_t l1; + int mode = '+'; /* Default to GCRYMPI_FMT_USG. */ + gcry_sexp_t freethis = NULL; + + memset (arrayisdesc, 0, sizeof arrayisdesc); + + /* First copy all the args into an array. This is required so that + we are able to release already allocated MPIs if later an error + was found. */ + for (s=list, idx=0; *s && idx < DIM (array); s++) + { + if (*s == '&' || *s == '+' || *s == '-' || *s == '/' || *s == '?' ) + ; + else + { + array[idx] = va_arg (arg_ptr, gcry_mpi_t *); + if (!array[idx]) + return GPG_ERR_MISSING_VALUE; /* NULL pointer given. */ + idx++; + } + } + if (*s) + return GPG_ERR_LIMIT_REACHED; /* Too many list elements. */ + if (va_arg (arg_ptr, gcry_mpi_t *)) + return GPG_ERR_INV_ARG; /* Not enough list elemends. */ + + /* Drill down. */ + while (path && *path) + { + size_t n; + + s = strchr (path, '!'); + if (s == path) + { + rc = GPG_ERR_NOT_FOUND; + goto cleanup; + } + n = s? s - path : 0; + l1 = gcry_sexp_find_token (sexp, path, n); + if (!l1) + { + rc = GPG_ERR_NOT_FOUND; + goto cleanup; + } + sexp = l1; l1 = NULL; + gcry_sexp_release (freethis); + freethis = sexp; + if (n) + path += n + 1; + else + path = NULL; + } + + + /* Now extract all parameters. */ + for (s=list, idx=0; *s; s++) + { + if (*s == '&' || *s == '+' || *s == '-' || *s == '/') + mode = *s; + else if (*s == '?') + ; /* Only used via lookahead. */ + else + { + l1 = gcry_sexp_find_token (sexp, s, 1); + if (!l1 && s[1] == '?') + { + /* Optional element not found. */ + if (mode == '&') + { + gcry_buffer_t *spec = (gcry_buffer_t*)array[idx]; + if (!spec->data) + { + spec->size = 0; + spec->off = 0; + } + spec->len = 0; + } + else + *array[idx] = NULL; + } + else if (!l1) + { + rc = GPG_ERR_NO_OBJ; /* List element not found. */ + goto cleanup; + } + else + { + if (mode == '&') + { + gcry_buffer_t *spec = (gcry_buffer_t*)array[idx]; + + if (spec->data) + { + const char *pbuf; + size_t nbuf; + + pbuf = gcry_sexp_nth_data (l1, 1, &nbuf); + if (!pbuf || !nbuf) + { + rc = GPG_ERR_INV_OBJ; + goto cleanup; + } + if (spec->off + nbuf > spec->size) + { + rc = GPG_ERR_BUFFER_TOO_SHORT; + goto cleanup; + } + memcpy ((char*)spec->data + spec->off, pbuf, nbuf); + spec->len = nbuf; + arrayisdesc[idx] = 1; + } + else + { + spec->data = gcry_sexp_nth_buffer (l1, 1, &spec->size); + if (!spec->data) + { + rc = GPG_ERR_INV_OBJ; /* Or out of core. */ + goto cleanup; + } + spec->len = spec->size; + spec->off = 0; + arrayisdesc[idx] = 2; + } + } + else if (mode == '/') + *array[idx] = _gcry_sexp_nth_opaque_mpi (l1, 1); + else if (mode == '-') + *array[idx] = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_STD); + else + *array[idx] = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); + gcry_sexp_release (l1); l1 = NULL; + if (!*array[idx]) + { + rc = GPG_ERR_INV_OBJ; /* Conversion failed. */ + goto cleanup; + } + } + idx++; + } + } + + gcry_sexp_release (freethis); + return 0; + + cleanup: + gcry_sexp_release (freethis); + gcry_sexp_release (l1); + while (idx--) + { + if (!arrayisdesc[idx]) + { + gcry_mpi_release (*array[idx]); + *array[idx] = NULL; + } + else if (!arrayisdesc[idx] == 1) + { + /* Caller provided buffer. */ + gcry_buffer_t *spec = (gcry_buffer_t*)array[idx]; + spec->len = 0; + } + else + { + /* We might have allocated a buffer. */ + gcry_buffer_t *spec = (gcry_buffer_t*)array[idx]; + gcry_free (spec->data); + spec->data = NULL; + spec->size = spec->off = spec->len = 0; + } + } + return rc; +} + +gpg_error_t +_gcry_sexp_extract_param (gcry_sexp_t sexp, const char *path, + const char *list, ...) +{ + gcry_err_code_t rc; + va_list arg_ptr; + + va_start (arg_ptr, list); + rc = _gcry_sexp_vextract_param (sexp, path, list, arg_ptr); + va_end (arg_ptr); + return gpg_error (rc); +} diff --git a/src/visibility.c b/src/visibility.c index 6e3c7550..848925e3 100644 --- a/src/visibility.c +++ b/src/visibility.c @@ -250,6 +250,21 @@ gcry_sexp_nth_mpi (gcry_sexp_t list, int number, int mpifmt) return _gcry_sexp_nth_mpi (list, number, mpifmt); } +gpg_error_t +gcry_sexp_extract_param (gcry_sexp_t sexp, const char *path, + const char *list, ...) +{ + gcry_err_code_t rc; + va_list arg_ptr; + + va_start (arg_ptr, list); + rc = _gcry_sexp_vextract_param (sexp, path, list, arg_ptr); + va_end (arg_ptr); + return gpg_error (rc); +} + + + gcry_mpi_t gcry_mpi_new (unsigned int nbits) { diff --git a/src/visibility.h b/src/visibility.h index cd2a60fb..1c8f0477 100644 --- a/src/visibility.h +++ b/src/visibility.h @@ -537,6 +537,7 @@ MARK_VISIBLE (gcry_sexp_release) MARK_VISIBLE (gcry_sexp_sprint) MARK_VISIBLE (gcry_sexp_sscan) MARK_VISIBLE (gcry_sexp_vlist) +MARK_VISIBLEX(gcry_sexp_extract_param) MARK_VISIBLEX(gcry_mpi_abs) MARK_VISIBLE (gcry_mpi_add) @@ -615,6 +616,16 @@ MARK_VISIBLEX(_gcry_mpi_get_const) #undef MARK_VISIBLE -#endif /*_GCRY_INCLUDED_BY_VISIBILITY_C*/ +#else /*!_GCRY_INCLUDED_BY_VISIBILITY_C*/ + +/* To avoid accidental use of the public functions inside Libgcrypt, + we redefine them to catch such errors. The usual difference + between a public and an internal version is that the internal + version use gpg_err_code_t and the public version gpg_error_t. */ + +#define gcry_sexp_extract_param _gcry_USE_THE_UNDERSCORED_FUNCTION + + +#endif /*!_GCRY_INCLUDED_BY_VISIBILITY_C*/ #endif /*GCRY_VISIBILITY_H*/ diff --git a/tests/tsexp.c b/tests/tsexp.c index 7c4f7c81..8a6b9128 100644 --- a/tests/tsexp.c +++ b/tests/tsexp.c @@ -25,14 +25,48 @@ #include <stdlib.h> #include <string.h> #include <stdarg.h> +#include <assert.h> #include "../src/gcrypt-int.h" #define PGMNAME "tsexp" +#ifndef DIM +# define DIM(v) (sizeof(v)/sizeof((v)[0])) +#endif +#define my_isascii(c) (!((c) & 0x80)) +#define digitp(p) (*(p) >= '0' && *(p) <= '9') +#define hexdigitp(a) (digitp (a) \ + || (*(a) >= 'A' && *(a) <= 'F') \ + || (*(a) >= 'a' && *(a) <= 'f')) +#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ + *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) +#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) +#define xmalloc(a) gcry_xmalloc ((a)) +#define xcalloc(a,b) gcry_xcalloc ((a),(b)) +#define xstrdup(a) gcry_xstrdup ((a)) +#define xfree(a) gcry_free ((a)) +#define pass() do { ; } while (0) + + static int verbose; static int error_count; static void +die (const char *format, ...) +{ + va_list arg_ptr ; + + fflush (stdout); + fprintf (stderr, "%s: ", PGMNAME); + va_start( arg_ptr, format ) ; + vfprintf (stderr, format, arg_ptr ); + va_end(arg_ptr); + if (*format && format[strlen(format)-1] != '\n') + putc ('\n', stderr); + exit (1); +} + +static void info (const char *format, ...) { va_list arg_ptr; @@ -42,6 +76,8 @@ info (const char *format, ...) va_start( arg_ptr, format ) ; vfprintf (stderr, format, arg_ptr ); va_end(arg_ptr); + if (*format && format[strlen(format)-1] != '\n') + putc ('\n', stderr); } } @@ -54,10 +90,110 @@ fail ( const char *format, ... ) va_start( arg_ptr, format ) ; vfprintf (stderr, format, arg_ptr ); va_end(arg_ptr); + if (*format && format[strlen(format)-1] != '\n') + putc ('\n', stderr); error_count++; } + +/* Convert STRING consisting of hex characters into its binary + representation and return it as an allocated buffer. The valid + length of the buffer is returned at R_LENGTH. The string is + delimited by end of string. The function returns NULL on + error. */ +static void * +hex2buffer (const char *string, size_t *r_length) +{ + const char *s; + unsigned char *buffer; + size_t length; + + buffer = xmalloc (strlen(string)/2+1); + length = 0; + for (s=string; *s; s +=2 ) + { + if (!hexdigitp (s) || !hexdigitp (s+1)) + return NULL; /* Invalid hex digits. */ + ((unsigned char*)buffer)[length++] = xtoi_2 (s); + } + *r_length = length; + return buffer; +} + + +static gcry_mpi_t +hex2mpi (const char *string) +{ + gpg_error_t err; + gcry_mpi_t val; + + err = gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL); + if (err) + die ("hex2mpi '%s' failed: %s\n", string, gpg_strerror (err)); + return val; +} + +static gcry_mpi_t +hex2mpiopa (const char *string) +{ + char *buffer; + size_t buflen; + gcry_mpi_t val; + + buffer = hex2buffer (string, &buflen); + if (!buffer) + die ("hex2mpiopa '%s' failed: parser error\n", string); + val = gcry_mpi_set_opaque (NULL, buffer, buflen*8); + if (!buffer) + die ("hex2mpiopa '%s' failed: set_opaque error%s\n", string); + return val; +} + + +/* Compare A to B, where B is given as a hex string. */ +static int +cmp_mpihex (gcry_mpi_t a, const char *b) +{ + gcry_mpi_t bval; + int res; + + if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)) + bval = hex2mpiopa (b); + else + bval = hex2mpi (b); + res = gcry_mpi_cmp (a, bval); + gcry_mpi_release (bval); + return res; +} + +/* Compare A to B, where A is a buffer and B a hex string. */ +static int +cmp_bufhex (const void *a, size_t alen, const char *b) +{ + void *bbuf; + size_t blen; + int res; + + if (!a && !b) + return 0; + if (a && !b) + return 1; + if (!a && b) + return -1; + + bbuf = hex2buffer (b, &blen); + if (!bbuf) + die ("cmp_bufhex: error converting hex string\n"); + if (alen != blen) + return alen < blen? -1 : 1; + res = memcmp (a, bbuf, alen); + xfree (bbuf); + return res; +} + + + /* fixme: we need better tests */ static void basic (void) @@ -195,7 +331,7 @@ basic (void) fail ("no car for `%s'\n", token); continue; } - info ("car=`%.*s'\n", (int)n, p); + /* info ("car=`%.*s'\n", (int)n, p); */ s2 = gcry_sexp_cdr (s1); if (!s2) @@ -230,7 +366,7 @@ basic (void) fail("no car for `%s'\n", parm ); continue; } - info ("car=`%.*s'\n", (int)n, p); + /* info ("car=`%.*s'\n", (int)n, p); */ p = gcry_sexp_nth_data (s2, 1, &n); if (!p) { @@ -238,7 +374,7 @@ basic (void) fail("no cdr for `%s'\n", parm ); continue; } - info ("cdr=`%.*s'\n", (int)n, p); + /* info ("cdr=`%.*s'\n", (int)n, p); */ a = gcry_sexp_nth_mpi (s2, 0, GCRYMPI_FMT_USG); gcry_sexp_release (s2); @@ -457,6 +593,379 @@ check_sscan (void) } +static void +check_extract_param (void) +{ + /* This sample data is a real key but with some parameters of the + public key modified. */ + static char sample1[] = + "(key-data" + " (public-key" + " (ecc" + " (curve Ed25519)" + " (p #6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED#)" + " (a #EF#)" + " (b #C2036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978B6#)" + " (g #14" + " 216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A" + " 6666666666666666666666666666666666666666666666666666666666666658#)" + " (n #0000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED#)" + " (q #20B37806015CA06B3AEB9423EE84A41D7F31AA65F4148553755206D679F8BF62#)" + "))" + " (private-key" + " (ecc" + " (curve Ed25519)" + " (p #7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED#)" + " (a #FF#)" + " (b #D2036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978B6#)" + " (g #04" + " 216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A" + " 6666666666666666666666666666666666666666666666666666666666666658#)" + " (n #1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED#)" + " (q #30B37806015CA06B3AEB9423EE84A41D7F31AA65F4148553755206D679F8BF62#)" + " (d #56BEA284A22F443A7AEA8CEFA24DA5055CDF1D490C94D8C568FE0802C9169276#)" + ")))"; + + static char sample1_p[] = + "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED"; + static char sample1_px[] = + "6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED"; + static char sample1_a[] = "FF"; + static char sample1_ax[] = "EF"; + static char sample1_b[] = + "D2036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978B6"; + static char sample1_bx[] = + "C2036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978B6"; + static char sample1_g[] = + "04" + "216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A" + "6666666666666666666666666666666666666666666666666666666666666658"; + static char sample1_gx[] = + "14" + "216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A" + "6666666666666666666666666666666666666666666666666666666666666658"; + static char sample1_n[] = + "1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED"; + static char sample1_nx[] = + "0000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED"; + static char sample1_q[] = + "30B37806015CA06B3AEB9423EE84A41D7F31AA65F4148553755206D679F8BF62"; + static char sample1_qx[] = + "20B37806015CA06B3AEB9423EE84A41D7F31AA65F4148553755206D679F8BF62"; + static char sample1_d[] = + "56BEA284A22F443A7AEA8CEFA24DA5055CDF1D490C94D8C568FE0802C9169276"; + + static struct { + const char *sexp_str; + const char *path; + const char *list; + int nparam; + gpg_err_code_t expected_err; + const char *exp_p; + const char *exp_a; + const char *exp_b; + const char *exp_g; + const char *exp_n; + const char *exp_q; + const char *exp_d; + } tests[] = { + { + sample1, + NULL, + "pabgnqd", 6, + GPG_ERR_MISSING_VALUE, + }, + { + sample1, + NULL, + "pabgnq", 7, + GPG_ERR_INV_ARG + }, + { + sample1, + NULL, + "pabgnqd", 7, + 0, + sample1_px, sample1_ax, sample1_bx, sample1_gx, sample1_nx, + sample1_qx, sample1_d + }, + { + sample1, + NULL, + "abg", 3, + 0, + sample1_ax, sample1_bx, sample1_gx + }, + { + sample1, + NULL, + "x?abg", 4, + 0, + NULL, sample1_ax, sample1_bx, sample1_gx + }, + { + sample1, + NULL, + "p?abg", 4, + GPG_ERR_USER_1, + NULL, sample1_ax, sample1_bx, sample1_gx + }, + { + sample1, + NULL, + "pax?gnqd", 7, + 0, + sample1_px, sample1_ax, NULL, sample1_gx, sample1_nx, + sample1_qx, sample1_d + }, + { + sample1, + "public-key", + "pabgnqd", 7, + GPG_ERR_NO_OBJ, /* d is not in public key. */ + sample1_px, sample1_ax, sample1_bx, sample1_gx, sample1_nx, + sample1_qx, sample1_d + }, + { + sample1, + "private-key", + "pabgnqd", 7, + 0, + sample1_p, sample1_a, sample1_b, sample1_g, sample1_n, + sample1_q, sample1_d + }, + { + sample1, + "public-key!ecc", + "pabgnq", 6, + 0, + sample1_px, sample1_ax, sample1_bx, sample1_gx, sample1_nx, + sample1_qx + }, + { + sample1, + "public-key!ecc!foo", + "pabgnq", 6, + GPG_ERR_NOT_FOUND + }, + { + sample1, + "public-key!!ecc", + "pabgnq", 6, + GPG_ERR_NOT_FOUND + }, + { + sample1, + "private-key", + "pa/bgnqd", 7, + 0, + sample1_p, sample1_a, sample1_b, sample1_g, sample1_n, + sample1_q, sample1_d + }, + { + sample1, + "private-key", + "p-a+bgnqd", 7, + 0, + sample1_p, "-01", sample1_b, sample1_g, sample1_n, + sample1_q, sample1_d + }, + {NULL} + }; + int idx, i; + const char *paramstr; + int paramidx; + gpg_error_t err; + gcry_sexp_t sxp; + gcry_mpi_t mpis[7]; + gcry_buffer_t ioarray[7]; + char iobuffer[200]; + + info ("checking gcry_sexp_extract_param\n"); + for (idx=0; tests[idx].sexp_str; idx++) + { + err = gcry_sexp_new (&sxp, tests[idx].sexp_str, 0, 1); + if (err) + die ("converting string to sexp failed: %s", gpg_strerror (err)); + + memset (mpis, 0, sizeof mpis); + switch (tests[idx].nparam) + { + case 0: + err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, + NULL); + break; + case 1: + err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, + mpis+0, NULL); + break; + case 2: + err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, + mpis+0, mpis+1, NULL); + break; + case 3: + err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, + mpis+0, mpis+1, mpis+2, NULL); + break; + case 4: + err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, + mpis+0, mpis+1, mpis+2, mpis+3, NULL); + break; + case 5: + err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, + mpis+0, mpis+1, mpis+2, mpis+3, mpis+4, + NULL); + break; + case 6: + err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, + mpis+0, mpis+1, mpis+2, mpis+3, mpis+4, + mpis+5, NULL); + break; + case 7: + err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, + mpis+0, mpis+1, mpis+2, mpis+3, mpis+4, + mpis+5, mpis+6, NULL); + break; + default: + die ("test %d: internal error", idx); + } + + if (tests[idx].expected_err + && tests[idx].expected_err != GPG_ERR_USER_1) + { + if (tests[idx].expected_err != gpg_err_code (err)) + fail ("gcry_sexp_extract_param test %d failed: " + "expected error '%s' - got '%s'", idx, + gpg_strerror (tests[idx].expected_err),gpg_strerror (err)); + + } + else if (err) + { + fail ("gcry_sexp_extract_param test %d failed: %s", + idx, gpg_strerror (err)); + } + else /* No error - check the extracted values. */ + { + for (paramidx=0; paramidx < DIM (mpis); paramidx++) + { + switch (paramidx) + { + case 0: paramstr = tests[idx].exp_p; break; + case 1: paramstr = tests[idx].exp_a; break; + case 2: paramstr = tests[idx].exp_b; break; + case 3: paramstr = tests[idx].exp_g; break; + case 4: paramstr = tests[idx].exp_n; break; + case 5: paramstr = tests[idx].exp_q; break; + case 6: paramstr = tests[idx].exp_d; break; + default: + die ("test %d: internal error: bad param %d", + idx, paramidx); + } + + if (tests[idx].expected_err == GPG_ERR_USER_1 + && mpis[paramidx] && !paramstr && paramidx == 0) + ; /* Okay Special case error for param 0. */ + else if (!mpis[paramidx] && !paramstr) + ; /* Okay. */ + else if (!mpis[paramidx] && paramstr) + fail ("test %d: value for param %d expected but not returned", + idx, paramidx); + else if (mpis[paramidx] && !paramstr) + fail ("test %d: value for param %d not expected", + idx, paramidx); + else if (cmp_mpihex (mpis[paramidx], paramstr)) + { + fail ("test %d: param %d mismatch", idx, paramidx); + gcry_log_debug ("expected: %s\n", paramstr); + gcry_log_debugmpi (" got", mpis[paramidx]); + } + else if (tests[idx].expected_err && paramidx == 0) + fail ("test %d: param %d: expected error '%s' - got 'Success'", + idx, paramidx, gpg_strerror (tests[idx].expected_err)); + } + + } + + for (i=0; i < DIM (mpis); i++) + gcry_mpi_release (mpis[i]); + gcry_sexp_release (sxp); + } + + info ("checking gcry_sexp_extract_param/desc\n"); + + memset (ioarray, 0, sizeof ioarray); + + err = gcry_sexp_new (&sxp, sample1, 0, 1); + if (err) + die ("converting string to sexp failed: %s", gpg_strerror (err)); + + ioarray[1].size = sizeof iobuffer; + ioarray[1].data = iobuffer; + ioarray[1].off = 0; + ioarray[2].size = sizeof iobuffer; + ioarray[2].data = iobuffer; + ioarray[2].off = 50; + assert (ioarray[2].off < sizeof iobuffer); + err = gcry_sexp_extract_param (sxp, "key-data!private-key", "&pab", + ioarray+0, ioarray+1, ioarray+2, NULL); + if (err) + fail ("gcry_sexp_extract_param with desc failed: %s", gpg_strerror (err)); + else + { + if (!ioarray[0].data) + fail ("gcry_sexp_extract_param/desc failed: no P"); + else if (ioarray[0].size != 32) + fail ("gcry_sexp_extract_param/desc failed: P has wrong size"); + else if (ioarray[0].len != 32) + fail ("gcry_sexp_extract_param/desc failed: P has wrong length"); + else if (ioarray[0].off) + fail ("gcry_sexp_extract_param/desc failed: P has OFF set"); + else if (cmp_bufhex (ioarray[0].data, ioarray[0].len, sample1_p)) + { + fail ("gcry_sexp_extract_param/desc failed: P mismatch"); + gcry_log_debug ("expected: %s\n", sample1_p); + gcry_log_debughex (" got", ioarray[0].data, ioarray[0].len); + } + + if (!ioarray[1].data) + fail ("gcry_sexp_extract_param/desc failed: A buffer lost"); + else if (ioarray[1].size != sizeof iobuffer) + fail ("gcry_sexp_extract_param/desc failed: A size changed"); + else if (ioarray[1].off != 0) + fail ("gcry_sexp_extract_param/desc failed: A off changed"); + else if (ioarray[1].len != 1) + fail ("gcry_sexp_extract_param/desc failed: A has wrong length"); + else if (cmp_bufhex (ioarray[1].data + ioarray[1].off, ioarray[1].len, + sample1_a)) + { + fail ("gcry_sexp_extract_param/desc failed: A mismatch"); + gcry_log_debug ("expected: %s\n", sample1_a); + gcry_log_debughex (" got", + ioarray[1].data + ioarray[1].off, ioarray[1].len); + } + + if (!ioarray[2].data) + fail ("gcry_sexp_extract_param/desc failed: B buffer lost"); + else if (ioarray[2].size != sizeof iobuffer) + fail ("gcry_sexp_extract_param/desc failed: B size changed"); + else if (ioarray[2].off != 50) + fail ("gcry_sexp_extract_param/desc failed: B off changed"); + else if (ioarray[2].len != 32) + fail ("gcry_sexp_extract_param/desc failed: B has wrong length"); + else if (cmp_bufhex (ioarray[2].data + ioarray[2].off, ioarray[2].len, + sample1_b)) + { + fail ("gcry_sexp_extract_param/desc failed: B mismatch"); + gcry_log_debug ("expected: %s\n", sample1_b); + gcry_log_debughex (" got", + ioarray[2].data + ioarray[2].off, ioarray[2].len); + } + + xfree (ioarray[0].data); + } + + gcry_sexp_release (sxp); +} int @@ -472,6 +981,7 @@ main (int argc, char **argv) canon_len (); back_and_forth (); check_sscan (); + check_extract_param (); return error_count? 1:0; } |