diff options
Diffstat (limited to 'src')
-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 |
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; @@ -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*/ |