Branch data Line data Source code
1 : : /*
2 : : * pgp-encrypt.c
3 : : * OpenPGP encrypt.
4 : : *
5 : : * Copyright (c) 2005 Marko Kreen
6 : : * All rights reserved.
7 : : *
8 : : * Redistribution and use in source and binary forms, with or without
9 : : * modification, are permitted provided that the following conditions
10 : : * are met:
11 : : * 1. Redistributions of source code must retain the above copyright
12 : : * notice, this list of conditions and the following disclaimer.
13 : : * 2. Redistributions in binary form must reproduce the above copyright
14 : : * notice, this list of conditions and the following disclaimer in the
15 : : * documentation and/or other materials provided with the distribution.
16 : : *
17 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 : : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 : : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 : : * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 : : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 : : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 : : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 : : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 : : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 : : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 : : * SUCH DAMAGE.
28 : : *
29 : : * contrib/pgcrypto/pgp-encrypt.c
30 : : */
31 : :
32 : : #include "postgres.h"
33 : :
34 : : #include <time.h>
35 : :
36 : : #include "mbuf.h"
37 : : #include "pgp.h"
38 : : #include "px.h"
39 : :
40 : : #define MDC_DIGEST_LEN 20
41 : : #define STREAM_ID 0xE0
42 : : #define STREAM_BLOCK_SHIFT 14
43 : :
44 : : static uint8 *
45 : 107 : render_newlen(uint8 *h, int len)
46 : : {
47 [ + + ]: 107 : if (len <= 191)
48 : : {
49 : 100 : *h++ = len & 255;
50 : : }
51 [ + - + + ]: 7 : else if (len > 191 && len <= 8383)
52 : : {
53 : 6 : *h++ = ((len - 192) >> 8) + 192;
54 : 6 : *h++ = (len - 192) & 255;
55 : : }
56 : : else
57 : : {
58 : 1 : *h++ = 255;
59 : 1 : *h++ = (len >> 24) & 255;
60 : 1 : *h++ = (len >> 16) & 255;
61 : 1 : *h++ = (len >> 8) & 255;
62 : 1 : *h++ = len & 255;
63 : : }
64 : 107 : return h;
65 : : }
66 : :
67 : : static int
68 : 79 : write_tag_only(PushFilter *dst, int tag)
69 : : {
70 : 79 : uint8 hdr = 0xC0 | tag;
71 : :
72 : 79 : return pushf_write(dst, &hdr, 1);
73 : : }
74 : :
75 : : static int
76 : 29 : write_normal_header(PushFilter *dst, int tag, int len)
77 : : {
78 : : uint8 hdr[8];
79 : 29 : uint8 *h = hdr;
80 : :
81 : 29 : *h++ = 0xC0 | tag;
82 : 29 : h = render_newlen(h, len);
83 : 29 : return pushf_write(dst, hdr, h - hdr);
84 : : }
85 : :
86 : :
87 : : /*
88 : : * MAC writer
89 : : */
90 : :
91 : : static int
92 : 34 : mdc_init(PushFilter *dst, void *init_arg, void **priv_p)
93 : : {
94 : : int res;
95 : : PX_MD *md;
96 : :
97 : 34 : res = pgp_load_digest(PGP_DIGEST_SHA1, &md);
98 [ - + ]: 34 : if (res < 0)
99 : 0 : return res;
100 : :
101 : 34 : *priv_p = md;
102 : 34 : return 0;
103 : : }
104 : :
105 : : static int
106 : 145 : mdc_write(PushFilter *dst, void *priv, const uint8 *data, int len)
107 : : {
108 : 145 : PX_MD *md = priv;
109 : :
110 : 145 : px_md_update(md, data, len);
111 : 145 : return pushf_write(dst, data, len);
112 : : }
113 : :
114 : : static int
115 : 34 : mdc_flush(PushFilter *dst, void *priv)
116 : : {
117 : : int res;
118 : : uint8 pkt[2 + MDC_DIGEST_LEN];
119 : 34 : PX_MD *md = priv;
120 : :
121 : : /*
122 : : * create mdc pkt
123 : : */
124 : 34 : pkt[0] = 0xD3;
125 : 34 : pkt[1] = 0x14; /* MDC_DIGEST_LEN */
126 : 34 : px_md_update(md, pkt, 2);
127 : 34 : px_md_finish(md, pkt + 2);
128 : :
129 : 34 : res = pushf_write(dst, pkt, 2 + MDC_DIGEST_LEN);
130 : 34 : px_memset(pkt, 0, 2 + MDC_DIGEST_LEN);
131 : 34 : return res;
132 : : }
133 : :
134 : : static void
135 : 33 : mdc_free(void *priv)
136 : : {
137 : 33 : PX_MD *md = priv;
138 : :
139 : 33 : px_md_free(md);
140 : 33 : }
141 : :
142 : : static const PushFilterOps mdc_filter = {
143 : : mdc_init, mdc_write, mdc_flush, mdc_free
144 : : };
145 : :
146 : :
147 : : /*
148 : : * Encrypted pkt writer
149 : : */
150 : : #define ENCBUF 8192
151 : : struct EncStat
152 : : {
153 : : PGP_CFB *ciph;
154 : : uint8 buf[ENCBUF];
155 : : };
156 : :
157 : : static int
158 : 35 : encrypt_init(PushFilter *next, void *init_arg, void **priv_p)
159 : : {
160 : : struct EncStat *st;
161 : 35 : PGP_Context *ctx = init_arg;
162 : : PGP_CFB *ciph;
163 : 35 : int resync = 1;
164 : : int res;
165 : :
166 : : /* should we use newer packet format? */
167 [ + + ]: 35 : if (ctx->disable_mdc == 0)
168 : : {
169 : 34 : uint8 ver = 1;
170 : :
171 : 34 : resync = 0;
172 : 34 : res = pushf_write(next, &ver, 1);
173 [ - + ]: 34 : if (res < 0)
174 : 0 : return res;
175 : : }
176 : 35 : res = pgp_cfb_create(&ciph, ctx->cipher_algo,
177 : 35 : ctx->sess_key, ctx->sess_key_len, resync, NULL,
178 : : 0 /* never ignore cipher failures for encrypt */ );
179 [ - + ]: 35 : if (res < 0)
180 : 0 : return res;
181 : :
182 : 35 : st = palloc0_object(struct EncStat);
183 : 35 : st->ciph = ciph;
184 : :
185 : 35 : *priv_p = st;
186 : 35 : return ENCBUF;
187 : : }
188 : :
189 : : static int
190 : 45 : encrypt_process(PushFilter *next, void *priv, const uint8 *data, int len)
191 : : {
192 : : int res;
193 : 45 : struct EncStat *st = priv;
194 : 45 : int avail = len;
195 : :
196 [ + + ]: 89 : while (avail > 0)
197 : : {
198 : 45 : int tmplen = avail > ENCBUF ? ENCBUF : avail;
199 : :
200 : 45 : res = pgp_cfb_encrypt(st->ciph, data, tmplen, st->buf);
201 [ - + ]: 44 : if (res < 0)
202 : 0 : return res;
203 : :
204 : 44 : res = pushf_write(next, st->buf, tmplen);
205 [ - + ]: 44 : if (res < 0)
206 : 0 : return res;
207 : :
208 : 44 : data += tmplen;
209 : 44 : avail -= tmplen;
210 : : }
211 : 44 : return 0;
212 : : }
213 : :
214 : : static void
215 : 34 : encrypt_free(void *priv)
216 : : {
217 : 34 : struct EncStat *st = priv;
218 : :
219 [ + - ]: 34 : if (st->ciph)
220 : 34 : pgp_cfb_free(st->ciph);
221 : 34 : px_memset(st, 0, sizeof(*st));
222 : 34 : pfree(st);
223 : 34 : }
224 : :
225 : : static const PushFilterOps encrypt_filter = {
226 : : encrypt_init, encrypt_process, NULL, encrypt_free
227 : : };
228 : :
229 : : /*
230 : : * Write Streamable pkts
231 : : */
232 : :
233 : : struct PktStreamStat
234 : : {
235 : : int final_done;
236 : : int pkt_block;
237 : : };
238 : :
239 : : static int
240 : 79 : pkt_stream_init(PushFilter *next, void *init_arg, void **priv_p)
241 : : {
242 : : struct PktStreamStat *st;
243 : :
244 : 79 : st = palloc_object(struct PktStreamStat);
245 : 79 : st->final_done = 0;
246 : 79 : st->pkt_block = 1 << STREAM_BLOCK_SHIFT;
247 : 79 : *priv_p = st;
248 : :
249 : 79 : return st->pkt_block;
250 : : }
251 : :
252 : : static int
253 : 87 : pkt_stream_process(PushFilter *next, void *priv, const uint8 *data, int len)
254 : : {
255 : : int res;
256 : : uint8 hdr[8];
257 : 87 : uint8 *h = hdr;
258 : 87 : struct PktStreamStat *st = priv;
259 : :
260 [ - + ]: 87 : if (st->final_done)
261 : 0 : return PXE_BUG;
262 : :
263 [ + + ]: 87 : if (len == st->pkt_block)
264 : 10 : *h++ = STREAM_ID | STREAM_BLOCK_SHIFT;
265 : : else
266 : : {
267 : 77 : h = render_newlen(h, len);
268 : 77 : st->final_done = 1;
269 : : }
270 : :
271 : 87 : res = pushf_write(next, hdr, h - hdr);
272 [ - + ]: 87 : if (res < 0)
273 : 0 : return res;
274 : :
275 : 87 : return pushf_write(next, data, len);
276 : : }
277 : :
278 : : static int
279 : 78 : pkt_stream_flush(PushFilter *next, void *priv)
280 : : {
281 : : int res;
282 : : uint8 hdr[8];
283 : 78 : uint8 *h = hdr;
284 : 78 : struct PktStreamStat *st = priv;
285 : :
286 : : /* stream MUST end with normal packet. */
287 [ + + ]: 78 : if (!st->final_done)
288 : : {
289 : 1 : h = render_newlen(h, 0);
290 : 1 : res = pushf_write(next, hdr, h - hdr);
291 [ - + ]: 1 : if (res < 0)
292 : 0 : return res;
293 : 1 : st->final_done = 1;
294 : : }
295 : 78 : return 0;
296 : : }
297 : :
298 : : static void
299 : 77 : pkt_stream_free(void *priv)
300 : : {
301 : 77 : struct PktStreamStat *st = priv;
302 : :
303 : 77 : px_memset(st, 0, sizeof(*st));
304 : 77 : pfree(st);
305 : 77 : }
306 : :
307 : : static const PushFilterOps pkt_stream_filter = {
308 : : pkt_stream_init, pkt_stream_process, pkt_stream_flush, pkt_stream_free
309 : : };
310 : :
311 : : int
312 : 6 : pgp_create_pkt_writer(PushFilter *dst, int tag, PushFilter **res_p)
313 : : {
314 : : int res;
315 : :
316 : 6 : res = write_tag_only(dst, tag);
317 [ - + ]: 6 : if (res < 0)
318 : 0 : return res;
319 : :
320 : 6 : return pushf_create(res_p, &pkt_stream_filter, NULL, dst);
321 : : }
322 : :
323 : : /*
324 : : * Text conversion filter
325 : : */
326 : :
327 : : static int
328 : 2 : crlf_process(PushFilter *dst, void *priv, const uint8 *data, int len)
329 : : {
330 : 2 : const uint8 *data_end = data + len;
331 : : const uint8 *p2,
332 : 2 : *p1 = data;
333 : : int line_len;
334 : : static const uint8 crlf[] = {'\r', '\n'};
335 : 2 : int res = 0;
336 : :
337 [ + + ]: 9 : while (p1 < data_end)
338 : : {
339 : 7 : p2 = memchr(p1, '\n', data_end - p1);
340 [ + + ]: 7 : if (p2 == NULL)
341 : 1 : p2 = data_end;
342 : :
343 : 7 : line_len = p2 - p1;
344 : :
345 : : /* write data */
346 : 7 : res = 0;
347 [ + - ]: 7 : if (line_len > 0)
348 : : {
349 : 7 : res = pushf_write(dst, p1, line_len);
350 [ - + ]: 7 : if (res < 0)
351 : 0 : break;
352 : 7 : p1 += line_len;
353 : : }
354 : :
355 : : /* write crlf */
356 [ + + + + ]: 14 : while (p1 < data_end && *p1 == '\n')
357 : : {
358 : 7 : res = pushf_write(dst, crlf, 2);
359 [ - + ]: 7 : if (res < 0)
360 : 0 : break;
361 : 7 : p1++;
362 : : }
363 : : }
364 : 2 : return res;
365 : : }
366 : :
367 : : static const PushFilterOps crlf_filter = {
368 : : NULL, crlf_process, NULL, NULL
369 : : };
370 : :
371 : : /*
372 : : * Initialize literal data packet
373 : : */
374 : : static int
375 : 35 : init_litdata_packet(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
376 : : {
377 : : int res;
378 : : int hdrlen;
379 : : uint8 hdr[6];
380 : : uint32 t;
381 : : PushFilter *pkt;
382 : : int type;
383 : :
384 : : /*
385 : : * Create header
386 : : */
387 : :
388 [ + + ]: 35 : if (ctx->text_mode)
389 [ - + ]: 31 : type = ctx->unicode_mode ? 'u' : 't';
390 : : else
391 : 4 : type = 'b';
392 : :
393 : : /*
394 : : * Store the creation time into packet. The goal is to have as few known
395 : : * bytes as possible.
396 : : */
397 : 35 : t = (uint32) time(NULL);
398 : :
399 : 35 : hdr[0] = type;
400 : 35 : hdr[1] = 0;
401 : 35 : hdr[2] = (t >> 24) & 255;
402 : 35 : hdr[3] = (t >> 16) & 255;
403 : 35 : hdr[4] = (t >> 8) & 255;
404 : 35 : hdr[5] = t & 255;
405 : 35 : hdrlen = 6;
406 : :
407 : 35 : res = write_tag_only(dst, PGP_PKT_LITERAL_DATA);
408 [ - + ]: 35 : if (res < 0)
409 : 0 : return res;
410 : :
411 : 35 : res = pushf_create(&pkt, &pkt_stream_filter, ctx, dst);
412 [ - + ]: 35 : if (res < 0)
413 : 0 : return res;
414 : :
415 : 35 : res = pushf_write(pkt, hdr, hdrlen);
416 [ - + ]: 35 : if (res < 0)
417 : : {
418 : 0 : pushf_free(pkt);
419 : 0 : return res;
420 : : }
421 : :
422 : 35 : *pf_res = pkt;
423 : 35 : return 0;
424 : : }
425 : :
426 : : /*
427 : : * Initialize compression filter
428 : : */
429 : : static int
430 : 3 : init_compress(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
431 : : {
432 : : int res;
433 : 3 : uint8 type = ctx->compress_algo;
434 : : PushFilter *pkt;
435 : :
436 : 3 : res = write_tag_only(dst, PGP_PKT_COMPRESSED_DATA);
437 [ - + ]: 3 : if (res < 0)
438 : 0 : return res;
439 : :
440 : 3 : res = pushf_create(&pkt, &pkt_stream_filter, ctx, dst);
441 [ - + ]: 3 : if (res < 0)
442 : 0 : return res;
443 : :
444 : 3 : res = pushf_write(pkt, &type, 1);
445 [ + - ]: 3 : if (res >= 0)
446 : 3 : res = pgp_compress_filter(pf_res, ctx, pkt);
447 : :
448 [ - + ]: 3 : if (res < 0)
449 : 0 : pushf_free(pkt);
450 : :
451 : 3 : return res;
452 : : }
453 : :
454 : : /*
455 : : * Initialize encdata packet
456 : : */
457 : : static int
458 : 35 : init_encdata_packet(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
459 : : {
460 : : int res;
461 : : int tag;
462 : :
463 [ + + ]: 35 : if (ctx->disable_mdc)
464 : 1 : tag = PGP_PKT_SYMENCRYPTED_DATA;
465 : : else
466 : 34 : tag = PGP_PKT_SYMENCRYPTED_DATA_MDC;
467 : :
468 : 35 : res = write_tag_only(dst, tag);
469 [ - + ]: 35 : if (res < 0)
470 : 0 : return res;
471 : :
472 : 35 : return pushf_create(pf_res, &pkt_stream_filter, ctx, dst);
473 : : }
474 : :
475 : : /*
476 : : * write prefix
477 : : */
478 : : static int
479 : 35 : write_prefix(PGP_Context *ctx, PushFilter *dst)
480 : : {
481 : : uint8 prefix[PGP_MAX_BLOCK + 2];
482 : : int res,
483 : : bs;
484 : :
485 : 35 : bs = pgp_get_cipher_block_size(ctx->cipher_algo);
486 [ - + ]: 35 : if (!pg_strong_random(prefix, bs))
487 : 0 : return PXE_NO_RANDOM;
488 : :
489 : 35 : prefix[bs + 0] = prefix[bs - 2];
490 : 35 : prefix[bs + 1] = prefix[bs - 1];
491 : :
492 : 35 : res = pushf_write(dst, prefix, bs + 2);
493 : 35 : px_memset(prefix, 0, bs + 2);
494 : 35 : return res < 0 ? res : 0;
495 : : }
496 : :
497 : : /*
498 : : * write symmetrically encrypted session key packet
499 : : */
500 : :
501 : : static int
502 : 4 : symencrypt_sesskey(PGP_Context *ctx, uint8 *dst)
503 : : {
504 : : int res;
505 : : PGP_CFB *cfb;
506 : 4 : uint8 algo = ctx->cipher_algo;
507 : :
508 : 4 : res = pgp_cfb_create(&cfb, ctx->s2k_cipher_algo,
509 : 4 : ctx->s2k.key, ctx->s2k.key_len, 0, NULL,
510 : : 0 /* never ignore cipher failures for encrypt */ );
511 [ - + ]: 4 : if (res < 0)
512 : 0 : return res;
513 : :
514 : 4 : pgp_cfb_encrypt(cfb, &algo, 1, dst);
515 : 3 : pgp_cfb_encrypt(cfb, ctx->sess_key, ctx->sess_key_len, dst + 1);
516 : :
517 : 3 : pgp_cfb_free(cfb);
518 : 3 : return ctx->sess_key_len + 1;
519 : : }
520 : :
521 : : /* 5.3: Symmetric-Key Encrypted Session-Key */
522 : : static int
523 : 30 : write_symenc_sesskey(PGP_Context *ctx, PushFilter *dst)
524 : : {
525 : : uint8 pkt[256];
526 : : int pktlen;
527 : : int res;
528 : 30 : uint8 *p = pkt;
529 : :
530 : 30 : *p++ = 4; /* 5.3 - version number */
531 : 30 : *p++ = ctx->s2k_cipher_algo;
532 : :
533 : 30 : *p++ = ctx->s2k.mode;
534 : 30 : *p++ = ctx->s2k.digest_algo;
535 [ + + ]: 30 : if (ctx->s2k.mode > 0)
536 : : {
537 : 29 : memcpy(p, ctx->s2k.salt, 8);
538 : 29 : p += 8;
539 : : }
540 [ + + ]: 30 : if (ctx->s2k.mode == 3)
541 : 28 : *p++ = ctx->s2k.iter;
542 : :
543 [ + + ]: 30 : if (ctx->use_sess_key)
544 : : {
545 : 4 : res = symencrypt_sesskey(ctx, p);
546 [ - + ]: 3 : if (res < 0)
547 : 0 : return res;
548 : 3 : p += res;
549 : : }
550 : :
551 : 29 : pktlen = p - pkt;
552 : 29 : res = write_normal_header(dst, PGP_PKT_SYMENCRYPTED_SESSKEY, pktlen);
553 [ + - ]: 29 : if (res >= 0)
554 : 29 : res = pushf_write(dst, pkt, pktlen);
555 : :
556 : 29 : px_memset(pkt, 0, pktlen);
557 : 29 : return res;
558 : : }
559 : :
560 : : /*
561 : : * key setup
562 : : */
563 : : static int
564 : 30 : init_s2k_key(PGP_Context *ctx)
565 : : {
566 : : int res;
567 : :
568 [ + - ]: 30 : if (ctx->s2k_cipher_algo < 0)
569 : 30 : ctx->s2k_cipher_algo = ctx->cipher_algo;
570 : :
571 : 30 : res = pgp_s2k_fill(&ctx->s2k, ctx->s2k_mode, ctx->s2k_digest_algo, ctx->s2k_count);
572 [ - + ]: 30 : if (res < 0)
573 : 0 : return res;
574 : :
575 : 30 : return pgp_s2k_process(&ctx->s2k, ctx->s2k_cipher_algo,
576 : : ctx->sym_key, ctx->sym_key_len);
577 : : }
578 : :
579 : : static int
580 : 36 : init_sess_key(PGP_Context *ctx)
581 : : {
582 [ + + + + ]: 36 : if (ctx->use_sess_key || ctx->pub_key)
583 : : {
584 : 10 : ctx->sess_key_len = pgp_get_cipher_key_size(ctx->cipher_algo);
585 [ - + ]: 10 : if (!pg_strong_random(ctx->sess_key, ctx->sess_key_len))
586 : 0 : return PXE_NO_RANDOM;
587 : : }
588 : : else
589 : : {
590 : 26 : ctx->sess_key_len = ctx->s2k.key_len;
591 : 26 : memcpy(ctx->sess_key, ctx->s2k.key, ctx->s2k.key_len);
592 : : }
593 : :
594 : 36 : return 0;
595 : : }
596 : :
597 : : /*
598 : : * combine
599 : : */
600 : : int
601 : 36 : pgp_encrypt(PGP_Context *ctx, MBuf *src, MBuf *dst)
602 : : {
603 : : int res;
604 : : int len;
605 : : uint8 *buf;
606 : : PushFilter *pf,
607 : : *pf_tmp;
608 : :
609 : : /*
610 : : * do we have any key
611 : : */
612 [ + + - + ]: 36 : if (!ctx->sym_key && !ctx->pub_key)
613 : 0 : return PXE_ARGUMENT_ERROR;
614 : :
615 : : /* MBuf writer */
616 : 36 : res = pushf_create_mbuf_writer(&pf, dst);
617 [ - + ]: 36 : if (res < 0)
618 : 0 : goto out;
619 : :
620 : : /*
621 : : * initialize sym_key
622 : : */
623 [ + + ]: 36 : if (ctx->sym_key)
624 : : {
625 : 30 : res = init_s2k_key(ctx);
626 [ - + ]: 30 : if (res < 0)
627 : 0 : goto out;
628 : : }
629 : :
630 : 36 : res = init_sess_key(ctx);
631 [ - + ]: 36 : if (res < 0)
632 : 0 : goto out;
633 : :
634 : : /*
635 : : * write keypkt
636 : : */
637 [ + + ]: 36 : if (ctx->pub_key)
638 : 6 : res = pgp_write_pubenc_sesskey(ctx, pf);
639 : : else
640 : 30 : res = write_symenc_sesskey(ctx, pf);
641 [ - + ]: 35 : if (res < 0)
642 : 0 : goto out;
643 : :
644 : : /* encrypted data pkt */
645 : 35 : res = init_encdata_packet(&pf_tmp, ctx, pf);
646 [ - + ]: 35 : if (res < 0)
647 : 0 : goto out;
648 : 35 : pf = pf_tmp;
649 : :
650 : : /* encrypter */
651 : 35 : res = pushf_create(&pf_tmp, &encrypt_filter, ctx, pf);
652 [ - + ]: 35 : if (res < 0)
653 : 0 : goto out;
654 : 35 : pf = pf_tmp;
655 : :
656 : : /* hasher */
657 [ + + ]: 35 : if (ctx->disable_mdc == 0)
658 : : {
659 : 34 : res = pushf_create(&pf_tmp, &mdc_filter, ctx, pf);
660 [ - + ]: 34 : if (res < 0)
661 : 0 : goto out;
662 : 34 : pf = pf_tmp;
663 : : }
664 : :
665 : : /* prefix */
666 : 35 : res = write_prefix(ctx, pf);
667 [ - + ]: 35 : if (res < 0)
668 : 0 : goto out;
669 : :
670 : : /* compressor */
671 [ + + + + ]: 35 : if (ctx->compress_algo > 0 && ctx->compress_level > 0)
672 : : {
673 : 3 : res = init_compress(&pf_tmp, ctx, pf);
674 [ - + ]: 3 : if (res < 0)
675 : 0 : goto out;
676 : 3 : pf = pf_tmp;
677 : : }
678 : :
679 : : /* data streamer */
680 : 35 : res = init_litdata_packet(&pf_tmp, ctx, pf);
681 [ - + ]: 35 : if (res < 0)
682 : 0 : goto out;
683 : 35 : pf = pf_tmp;
684 : :
685 : :
686 : : /* text conversion? */
687 [ + + + + ]: 35 : if (ctx->text_mode && ctx->convert_crlf)
688 : : {
689 : 2 : res = pushf_create(&pf_tmp, &crlf_filter, ctx, pf);
690 [ - + ]: 2 : if (res < 0)
691 : 0 : goto out;
692 : 2 : pf = pf_tmp;
693 : : }
694 : :
695 : : /*
696 : : * chain complete
697 : : */
698 : :
699 : 35 : len = mbuf_grab(src, mbuf_avail(src), &buf);
700 : 35 : res = pushf_write(pf, buf, len);
701 [ - + ]: 35 : if (res >= 0)
702 : 35 : res = pushf_flush(pf);
703 : 0 : out:
704 : 34 : pushf_free_all(pf);
705 : 34 : return res;
706 : : }
|