summaryrefslogtreecommitdiffstats
path: root/src/librepgp/stream-common.h
blob: 02279d3bae72c2a1488ebf19de348770d24c5e3b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
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