summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2013-10-16 16:20:56 +0200
committerWerner Koch <wk@gnupg.org>2013-10-16 16:20:56 +0200
commita329b6abf00c990faf1986f9fbad7b4d71c13bcb (patch)
tree52b1f995cbc863404fb8a01005f3d17c29706655
parent45aa6131e93fac89d46733b3436d960f35fb99b2 (diff)
downloadlibgcrypt-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--NEWS5
-rw-r--r--cipher/dsa.c16
-rw-r--r--cipher/ecc-curves.c6
-rw-r--r--cipher/ecc-misc.c1
-rw-r--r--cipher/ecc.c38
-rw-r--r--cipher/elgamal.c27
-rw-r--r--cipher/pubkey-internal.h3
-rw-r--r--cipher/pubkey-util.c113
-rw-r--r--cipher/rsa.c26
-rw-r--r--doc/gcrypt.texi60
-rw-r--r--src/g10lib.h13
-rw-r--r--src/gcrypt.h.in15
-rw-r--r--src/libgcrypt.def3
-rw-r--r--src/libgcrypt.vers2
-rw-r--r--src/sexp.c235
-rw-r--r--src/visibility.c15
-rw-r--r--src/visibility.h13
-rw-r--r--tests/tsexp.c516
18 files changed, 920 insertions, 187 deletions
diff --git a/NEWS b/NEWS
index ab326eb2..d60e0671 100644
--- a/NEWS
+++ b/NEWS
@@ -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;
diff --git a/src/sexp.c b/src/sexp.c
index 6a2a9be6..6e4ff27a 100644
--- a/src/sexp.c
+++ b/src/sexp.c
@@ -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;
}