summaryrefslogtreecommitdiffstats
path: root/src/librepgp/stream-common.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/librepgp/stream-common.h')
-rw-r--r--src/librepgp/stream-common.h556
1 files changed, 556 insertions, 0 deletions
diff --git a/src/librepgp/stream-common.h b/src/librepgp/stream-common.h
new file mode 100644
index 0000000..02279d3
--- /dev/null
+++ b/src/librepgp/stream-common.h
@@ -0,0 +1,556 @@
+/*
+ * Copyright (c) 2017-2020, [Ribose Inc](https://www.ribose.com).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef STREAM_COMMON_H_
+#define STREAM_COMMON_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include "types.h"
+
+#define PGP_INPUT_CACHE_SIZE 32768
+#define PGP_OUTPUT_CACHE_SIZE 32768
+
+#define PGP_PARTIAL_PKT_FIRST_PART_MIN_SIZE 512
+
+typedef enum {
+ PGP_STREAM_NULL,
+ PGP_STREAM_FILE,
+ PGP_STREAM_MEMORY,
+ PGP_STREAM_STDIN,
+ PGP_STREAM_STDOUT,
+ PGP_STREAM_PACKET,
+ PGP_STREAM_PARLEN_PACKET,
+ PGP_STREAM_LITERAL,
+ PGP_STREAM_COMPRESSED,
+ PGP_STREAM_ENCRYPTED,
+ PGP_STREAM_SIGNED,
+ PGP_STREAM_ARMORED,
+ PGP_STREAM_CLEARTEXT
+} pgp_stream_type_t;
+
+typedef struct pgp_source_t pgp_source_t;
+typedef struct pgp_dest_t pgp_dest_t;
+
+typedef bool pgp_source_read_func_t(pgp_source_t *src, void *buf, size_t len, size_t *read);
+typedef rnp_result_t pgp_source_finish_func_t(pgp_source_t *src);
+typedef void pgp_source_close_func_t(pgp_source_t *src);
+
+typedef rnp_result_t pgp_dest_write_func_t(pgp_dest_t *dst, const void *buf, size_t len);
+typedef rnp_result_t pgp_dest_finish_func_t(pgp_dest_t *src);
+typedef void pgp_dest_close_func_t(pgp_dest_t *dst, bool discard);
+
+/* statically preallocated cache for sources */
+typedef struct pgp_source_cache_t {
+ uint8_t buf[PGP_INPUT_CACHE_SIZE];
+ unsigned pos; /* current position in cache */
+ unsigned len; /* number of bytes available in cache */
+ bool readahead; /* whether read-ahead with larger chunks allowed */
+} pgp_source_cache_t;
+
+typedef struct pgp_source_t {
+ pgp_source_read_func_t * read;
+ pgp_source_finish_func_t *finish;
+ pgp_source_close_func_t * close;
+ pgp_stream_type_t type;
+
+ uint64_t size; /* size of the data if available, see knownsize */
+ uint64_t readb; /* number of bytes read from the stream via src_read. Do not confuse with
+ number of bytes as returned via the read since data may be cached */
+ pgp_source_cache_t *cache; /* cache if used */
+ void * param; /* source-specific additional data */
+
+ unsigned eof : 1; /* end of data as reported by read and empty cache */
+ unsigned knownsize : 1; /* whether size of the data is known */
+ unsigned error : 1; /* there were reading error */
+} pgp_source_t;
+
+/** @brief helper function to allocate memory for source's cache and param
+ * Also fills src and param with zeroes
+ * @param src pointer to the source structure
+ * @param paramsize number of bytes required for src->param
+ * @return true on success or false if memory allocation failed.
+ **/
+bool init_src_common(pgp_source_t *src, size_t paramsize);
+
+/** @brief read up to len bytes from the source
+ * While this function tries to read as much bytes as possible however it may return
+ * less then len bytes. Then src->eof can be checked if it's end of data.
+ *
+ * @param src source structure
+ * @param buf preallocated buffer which can store up to len bytes
+ * @param len number of bytes to read
+ * @param read number of read bytes will be stored here. Cannot be NULL.
+ * @return true on success or false otherwise
+ **/
+bool src_read(pgp_source_t *src, void *buf, size_t len, size_t *read);
+
+/** @brief shortcut to read exactly len bytes from source. See src_read for parameters.
+ * @return true if len bytes were read or false otherwise (i.e. less then len were read or
+ * read error occurred) */
+bool src_read_eq(pgp_source_t *src, void *buf, size_t len);
+
+/** @brief read up to len bytes and keep them in the cache/do not process
+ * Works only for streams with cache
+ * @param src source structure
+ * @param buf preallocated buffer which can store up to len bytes, or NULL if data should be
+ * discarded, just making sure that needed input is available in source
+ * @param len number of bytes to read. Must be less then PGP_INPUT_CACHE_SIZE.
+ * @param read number of bytes read will be stored here. Cannot be NULL.
+ * @return true on success or false otherwise
+ **/
+bool src_peek(pgp_source_t *src, void *buf, size_t len, size_t *read);
+
+/** @brief shortcut to read exactly len bytes and keep them in the cache/do not process
+ * Works only for streams with cache
+ * @return true if len bytes were read or false otherwise (i.e. less then len were read or
+ * read error occurred) */
+bool src_peek_eq(pgp_source_t *src, void *buf, size_t len);
+
+/** @brief skip up to len bytes.
+ * Note: use src_read() if you want to check error condition/get number of bytes
+ *skipped.
+ * @param src source structure
+ * @param len number of bytes to skip
+ **/
+void src_skip(pgp_source_t *src, size_t len);
+
+/** @brief notify source that all reading is done, so final data processing may be started,
+ * i.e. signature reading and verification and so on. Do not misuse with src_close.
+ * @param src allocated and initialized source structure
+ * @return RNP_SUCCESS or error code. If source doesn't have finish handler then also
+ * RNP_SUCCESS is returned
+ */
+rnp_result_t src_finish(pgp_source_t *src);
+
+/** @brief check whether there were reading error on source
+ * @param allocated and initialized source structure
+ * @return true if there were reading error or false otherwise
+ */
+bool src_error(const pgp_source_t *src);
+
+/** @brief check whether there is no more input on source
+ * @param src allocated and initialized source structure
+ * @return true if there is no more input or false otherwise.
+ * On read error false will be returned.
+ */
+bool src_eof(pgp_source_t *src);
+
+/** @brief close the source and deallocate all internal resources if any
+ */
+void src_close(pgp_source_t *src);
+
+/** @brief skip end of line on the source (\r\n or \n, depending on input)
+ * @param src allocated and initialized source
+ * @return true if eol was found and skipped or false otherwise
+ */
+bool src_skip_eol(pgp_source_t *src);
+
+/** @brief peek the line on the source
+ * @param src allocated and initialized source with data
+ * @param buf preallocated buffer to store the result. Result include NULL character and
+ * doesn't include the end of line sequence.
+ * @param len maximum length of data to store in buf, including terminating NULL
+ * @param read on success here will be stored number of bytes in the string, without the NULL
+ * character.
+ * @return true on success
+ * false is returned if there were eof, read error or eol was not found within the
+ * len. Supported eol sequences are \r\n and \n
+ */
+bool src_peek_line(pgp_source_t *src, char *buf, size_t len, size_t *read);
+
+/** @brief init file source
+ * @param src pre-allocated source structure
+ * @param path path to the file
+ * @return RNP_SUCCESS or error code
+ **/
+rnp_result_t init_file_src(pgp_source_t *src, const char *path);
+
+/** @brief init stdin source
+ * @param src pre-allocated source structure
+ * @return RNP_SUCCESS or error code
+ **/
+rnp_result_t init_stdin_src(pgp_source_t *src);
+
+/** @brief init memory source
+ * @param src pre-allocated source structure
+ * @param mem memory to read from
+ * @param len number of bytes in input
+ * @param free free the memory pointer on stream close or not
+ * @return RNP_SUCCESS or error code
+ **/
+rnp_result_t init_mem_src(pgp_source_t *src, const void *mem, size_t len, bool free);
+
+/** @brief init NULL source, which doesn't allow to read anything and always returns an error.
+ * @param src pre-allocated source structure
+ * @return always RNP_SUCCESS
+ **/
+rnp_result_t init_null_src(pgp_source_t *src);
+
+/** @brief init memory source with contents of other source
+ * @param src pre-allocated source structure
+ * @param readsrc opened source with data
+ * @return RNP_SUCCESS or error code
+ **/
+rnp_result_t read_mem_src(pgp_source_t *src, pgp_source_t *readsrc);
+
+/** @brief init memory source with contents of the specified file
+ * @param src pre-allocated source structure
+ * @param filename name of the file
+ * @return RNP_SUCCESS or error code
+ **/
+rnp_result_t file_to_mem_src(pgp_source_t *src, const char *filename);
+
+/** @brief get memory from the memory source
+ * @param src initialized memory source
+ * @param own transfer ownership of the memory
+ * @return pointer to the memory or NULL if it is not a memory source
+ **/
+const void *mem_src_get_memory(pgp_source_t *src, bool own = false);
+
+typedef struct pgp_dest_t {
+ pgp_dest_write_func_t * write;
+ pgp_dest_finish_func_t *finish;
+ pgp_dest_close_func_t * close;
+ pgp_stream_type_t type;
+ rnp_result_t werr; /* write function may set this to some error code */
+
+ size_t writeb; /* number of bytes written */
+ void * param; /* source-specific additional data */
+ bool no_cache; /* disable write caching */
+ uint8_t cache[PGP_OUTPUT_CACHE_SIZE];
+ unsigned clen; /* number of bytes in cache */
+ bool finished; /* whether dst_finish was called on dest or not */
+} pgp_dest_t;
+
+/** @brief helper function to allocate memory for dest's param.
+ * Initializes dst and param with zeroes as well.
+ * @param dst dest structure
+ * @param paramsize number of bytes required for dst->param
+ * @return true on success, or false if memory allocation failed
+ **/
+bool init_dst_common(pgp_dest_t *dst, size_t paramsize);
+
+/** @brief write buffer to the destination
+ *
+ * @param dst destination structure
+ * @param buf buffer with data
+ * @param len number of bytes to write
+ * @return true on success or false otherwise
+ **/
+void dst_write(pgp_dest_t *dst, const void *buf, size_t len);
+
+/** @brief printf formatted string to the destination
+ *
+ * @param dst destination structure
+ * @param format format string, which is the same as printf() uses
+ * @param ... additional arguments
+ */
+void dst_printf(pgp_dest_t *dst, const char *format, ...);
+
+/** @brief do all finalization tasks after all writing is done, i.e. calculate and write
+ * mdc, signatures and so on. Do not misuse with dst_close. If was not called then will be
+ * called from the dst_close
+ *
+ * @param dst destination structure
+ * @return RNP_SUCCESS or error code if something went wrong
+ **/
+rnp_result_t dst_finish(pgp_dest_t *dst);
+
+/** @brief close the destination
+ *
+ * @param dst destination structure to be closed
+ * @param discard if this is true then all produced output should be discarded
+ * @return void
+ **/
+void dst_close(pgp_dest_t *dst, bool discard);
+
+/** @brief flush cached data if any. dst_write caches small writes, so data does not
+ * immediately go to stream write function.
+ *
+ * @param dst destination structure
+ * @return void
+ **/
+void dst_flush(pgp_dest_t *dst);
+
+/** @brief init file destination
+ * @param dst pre-allocated dest structure
+ * @param path path to the file
+ * @param overwrite overwrite existing file
+ * @return RNP_SUCCESS or error code
+ **/
+rnp_result_t init_file_dest(pgp_dest_t *dst, const char *path, bool overwrite);
+
+/** @brief init file destination, using the temporary file name, based on path.
+ * Once writing is over, dst_finish() will attempt to rename to the desired name.
+ * @param dst pre-allocated dest structure
+ * @param path path to the file
+ * @param overwrite overwrite existing file on rename
+ * @return RNP_SUCCESS or error code
+ **/
+rnp_result_t init_tmpfile_dest(pgp_dest_t *dst, const char *path, bool overwrite);
+
+/** @brief init stdout destination
+ * @param dst pre-allocated dest structure
+ * @return RNP_SUCCESS or error code
+ **/
+rnp_result_t init_stdout_dest(pgp_dest_t *dst);
+
+/** @brief init memory destination
+ * @param dst pre-allocated dest structure
+ * @param mem pointer to the pre-allocated memory buffer, or NULL if it should be allocated
+ * @param len number of bytes which mem can keep, or maximum amount of memory to allocate if
+ * mem is NULL. If len is zero in later case then allocation is not limited.
+ * @return RNP_SUCCESS or error code
+ **/
+rnp_result_t init_mem_dest(pgp_dest_t *dst, void *mem, unsigned len);
+
+/** @brief set whether to silently discard bytes which overflow memory of the dst.
+ * @param dst pre-allocated and initialized memory dest
+ * @param discard true to discard or false to return an error on overflow.
+ **/
+void mem_dest_discard_overflow(pgp_dest_t *dst, bool discard);
+
+/** @brief get the pointer to the memory where data is written.
+ * Do not retain the result, it may change between calls due to realloc
+ * @param dst pre-allocated and initialized memory dest
+ * @return pointer to the memory area or NULL if memory was not allocated
+ **/
+void *mem_dest_get_memory(pgp_dest_t *dst);
+
+/** @brief get ownership on the memory dest's contents. This must be called only before
+ * closing the dest
+ * @param dst pre-allocated and initialized memory dest
+ * @return pointer to the memory area or NULL if memory was not allocated (i.e. nothing was
+ * written to the destination). Also NULL will be returned on possible (re-)allocation
+ * failure, this case can be identified by non-zero dst->writeb.
+ **/
+void *mem_dest_own_memory(pgp_dest_t *dst);
+
+/** @brief mark memory dest as secure, so it will be deallocated securely
+ * @param dst pre-allocated and initialized memory dest
+ * @param secure whether memory should be considered as secure or not
+ * @return void
+ **/
+void mem_dest_secure_memory(pgp_dest_t *dst, bool secure);
+
+/** @brief init null destination which silently discards all the output
+ * @param dst pre-allocated dest structure
+ * @return RNP_SUCCESS or error code
+ **/
+rnp_result_t init_null_dest(pgp_dest_t *dst);
+
+/** @brief reads from source and writes to destination
+ * @param src initialized source
+ * @param dst initialized destination
+ * @param limit sets the maximum amount of bytes to be read,
+ * returning an error if the source hasn't come to eof after that amount
+ * if 0, no limit is imposed
+ * @return RNP_SUCCESS or error code
+ **/
+rnp_result_t dst_write_src(pgp_source_t *src, pgp_dest_t *dst, uint64_t limit = 0);
+
+namespace rnp {
+/* Temporary wrapper to destruct stack-based pgp_source_t */
+class Source {
+ protected:
+ pgp_source_t src_;
+
+ public:
+ Source(const Source &) = delete;
+ Source(Source &&) = delete;
+
+ Source() : src_({})
+ {
+ }
+
+ virtual ~Source()
+ {
+ src_close(&src_);
+ }
+
+ virtual pgp_source_t &
+ src()
+ {
+ return src_;
+ }
+
+ size_t
+ size()
+ {
+ return src().size;
+ }
+
+ size_t
+ readb()
+ {
+ return src().readb;
+ }
+
+ bool
+ eof()
+ {
+ return src_eof(&src());
+ }
+
+ bool
+ error()
+ {
+ return src_error(&src());
+ }
+};
+
+class MemorySource : public Source {
+ public:
+ MemorySource(const MemorySource &) = delete;
+ MemorySource(MemorySource &&) = delete;
+
+ /**
+ * @brief Construct memory source object.
+ *
+ * @param mem source memory. Must be valid for the whole lifetime of the object.
+ * @param len size of the memory.
+ * @param free free memory once processing is finished.
+ */
+ MemorySource(const void *mem, size_t len, bool free) : Source()
+ {
+ auto res = init_mem_src(&src_, mem, len, free);
+ if (res) {
+ throw std::bad_alloc();
+ }
+ }
+
+ /**
+ * @brief Construct memory source object
+ *
+ * @param vec vector with data. Must be valid for the whole lifetime of the object.
+ */
+ MemorySource(const std::vector<uint8_t> &vec) : MemorySource(vec.data(), vec.size(), false)
+ {
+ }
+
+ MemorySource(pgp_source_t &src) : Source()
+ {
+ auto res = read_mem_src(&src_, &src);
+ if (res) {
+ throw rnp::rnp_exception(res);
+ }
+ }
+
+ const void *
+ memory(bool own = false)
+ {
+ return mem_src_get_memory(&src_, own);
+ }
+};
+
+/* Temporary wrapper to destruct stack-based pgp_dest_t */
+class Dest {
+ protected:
+ pgp_dest_t dst_;
+ bool discard_;
+
+ public:
+ Dest(const Dest &) = delete;
+ Dest(Dest &&) = delete;
+
+ Dest() : dst_({}), discard_(false)
+ {
+ }
+
+ virtual ~Dest()
+ {
+ dst_close(&dst_, discard_);
+ }
+
+ void
+ write(const void *buf, size_t len)
+ {
+ dst_write(&dst_, buf, len);
+ }
+
+ void
+ set_discard(bool discard)
+ {
+ discard_ = discard;
+ }
+
+ pgp_dest_t &
+ dst()
+ {
+ return dst_;
+ }
+
+ size_t
+ writeb()
+ {
+ return dst_.writeb;
+ }
+
+ rnp_result_t
+ werr()
+ {
+ return dst_.werr;
+ }
+};
+
+class MemoryDest : public Dest {
+ public:
+ MemoryDest(const MemoryDest &) = delete;
+ MemoryDest(MemoryDest &&) = delete;
+
+ MemoryDest(void *mem = NULL, size_t len = 0) : Dest()
+ {
+ auto res = init_mem_dest(&dst_, mem, len);
+ if (res) {
+ throw std::bad_alloc();
+ }
+ discard_ = true;
+ }
+
+ void *
+ memory()
+ {
+ return mem_dest_get_memory(&dst_);
+ }
+
+ void
+ set_secure(bool secure)
+ {
+ mem_dest_secure_memory(&dst_, secure);
+ }
+
+ std::vector<uint8_t>
+ to_vector()
+ {
+ uint8_t *mem = (uint8_t *) memory();
+ return std::vector<uint8_t>(mem, mem + writeb());
+ }
+};
+} // namespace rnp
+
+#endif