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