summaryrefslogtreecommitdiff
path: root/src
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 /src
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>
Diffstat (limited to 'src')
-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
7 files changed, 286 insertions, 10 deletions
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*/