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

Generated by: LCOV version 1.13