LCOV - code coverage report
Current view: top level - contrib/pgcrypto - pgp-encrypt.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 261 298 87.6 %
Date: 2024-04-25 23:11:32 Functions: 25 25 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14