LCOV - code coverage report
Current view: top level - contrib/pgcrypto - pgp-encrypt.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 87.6 % 298 261
Test Date: 2026-03-04 08:14:57 Functions: 100.0 % 25 25
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          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
      68           81 : write_tag_only(PushFilter *dst, int tag)
      69              : {
      70           81 :     uint8       hdr = 0xC0 | tag;
      71              : 
      72           81 :     return pushf_write(dst, &hdr, 1);
      73              : }
      74              : 
      75              : static int
      76           30 : write_normal_header(PushFilter *dst, int tag, int len)
      77              : {
      78              :     uint8       hdr[8];
      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
      92           35 : mdc_init(PushFilter *dst, void *init_arg, void **priv_p)
      93              : {
      94              :     int         res;
      95              :     PX_MD      *md;
      96              : 
      97           35 :     res = pgp_load_digest(PGP_DIGEST_SHA1, &md);
      98           35 :     if (res < 0)
      99            0 :         return res;
     100              : 
     101           35 :     *priv_p = md;
     102           35 :     return 0;
     103              : }
     104              : 
     105              : static int
     106          149 : mdc_write(PushFilter *dst, void *priv, const uint8 *data, int len)
     107              : {
     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
     115           35 : mdc_flush(PushFilter *dst, void *priv)
     116              : {
     117              :     int         res;
     118              :     uint8       pkt[2 + MDC_DIGEST_LEN];
     119           35 :     PX_MD      *md = priv;
     120              : 
     121              :     /*
     122              :      * create mdc pkt
     123              :      */
     124           35 :     pkt[0] = 0xD3;
     125           35 :     pkt[1] = 0x14;              /* MDC_DIGEST_LEN */
     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);
     130           35 :     px_memset(pkt, 0, 2 + MDC_DIGEST_LEN);
     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
     158           36 : encrypt_init(PushFilter *next, void *init_arg, void **priv_p)
     159              : {
     160              :     struct EncStat *st;
     161           36 :     PGP_Context *ctx = init_arg;
     162              :     PGP_CFB    *ciph;
     163           36 :     int         resync = 1;
     164              :     int         res;
     165              : 
     166              :     /* should we use newer packet format? */
     167           36 :     if (ctx->disable_mdc == 0)
     168              :     {
     169           35 :         uint8       ver = 1;
     170              : 
     171           35 :         resync = 0;
     172           35 :         res = pushf_write(next, &ver, 1);
     173           35 :         if (res < 0)
     174            0 :             return res;
     175              :     }
     176           36 :     res = pgp_cfb_create(&ciph, ctx->cipher_algo,
     177           36 :                          ctx->sess_key, ctx->sess_key_len, resync, NULL);
     178           36 :     if (res < 0)
     179            0 :         return res;
     180              : 
     181           36 :     st = palloc0_object(struct EncStat);
     182           36 :     st->ciph = ciph;
     183              : 
     184           36 :     *priv_p = st;
     185           36 :     return ENCBUF;
     186              : }
     187              : 
     188              : static int
     189           46 : encrypt_process(PushFilter *next, void *priv, const uint8 *data, int len)
     190              : {
     191              :     int         res;
     192           46 :     struct EncStat *st = priv;
     193           46 :     int         avail = len;
     194              : 
     195           92 :     while (avail > 0)
     196              :     {
     197           46 :         int         tmplen = avail > ENCBUF ? ENCBUF : avail;
     198              : 
     199           46 :         res = pgp_cfb_encrypt(st->ciph, data, tmplen, st->buf);
     200           46 :         if (res < 0)
     201            0 :             return res;
     202              : 
     203           46 :         res = pushf_write(next, st->buf, tmplen);
     204           46 :         if (res < 0)
     205            0 :             return res;
     206              : 
     207           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              : 
     218           36 :     if (st->ciph)
     219           36 :         pgp_cfb_free(st->ciph);
     220           36 :     px_memset(st, 0, sizeof(*st));
     221           36 :     pfree(st);
     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
     239           81 : pkt_stream_init(PushFilter *next, void *init_arg, void **priv_p)
     240              : {
     241              :     struct PktStreamStat *st;
     242              : 
     243           81 :     st = palloc_object(struct PktStreamStat);
     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
     252           90 : pkt_stream_process(PushFilter *next, void *priv, const uint8 *data, int len)
     253              : {
     254              :     int         res;
     255              :     uint8       hdr[8];
     256           90 :     uint8      *h = hdr;
     257           90 :     struct PktStreamStat *st = priv;
     258              : 
     259           90 :     if (st->final_done)
     260            0 :         return PXE_BUG;
     261              : 
     262           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)
     272            0 :         return res;
     273              : 
     274           90 :     return pushf_write(next, data, len);
     275              : }
     276              : 
     277              : static int
     278           81 : pkt_stream_flush(PushFilter *next, void *priv)
     279              : {
     280              :     int         res;
     281              :     uint8       hdr[8];
     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)
     291            0 :             return res;
     292            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              : 
     302           81 :     px_memset(st, 0, sizeof(*st));
     303           81 :     pfree(st);
     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
     311            6 : pgp_create_pkt_writer(PushFilter *dst, int tag, PushFilter **res_p)
     312              : {
     313              :     int         res;
     314              : 
     315            6 :     res = write_tag_only(dst, tag);
     316            6 :     if (res < 0)
     317            0 :         return res;
     318              : 
     319            6 :     return pushf_create(res_p, &pkt_stream_filter, NULL, dst);
     320              : }
     321              : 
     322              : /*
     323              :  * Text conversion filter
     324              :  */
     325              : 
     326              : static int
     327            2 : crlf_process(PushFilter *dst, void *priv, const uint8 *data, int len)
     328              : {
     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              : 
     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)
     350            0 :                 break;
     351            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)
     359            0 :                 break;
     360            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
     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              : 
     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              :      */
     396           36 :     t = (uint32) time(NULL);
     397              : 
     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)
     408            0 :         return res;
     409              : 
     410           36 :     res = pushf_create(&pkt, &pkt_stream_filter, ctx, dst);
     411           36 :     if (res < 0)
     412            0 :         return res;
     413              : 
     414           36 :     res = pushf_write(pkt, hdr, hdrlen);
     415           36 :     if (res < 0)
     416              :     {
     417            0 :         pushf_free(pkt);
     418            0 :         return res;
     419              :     }
     420              : 
     421           36 :     *pf_res = pkt;
     422           36 :     return 0;
     423              : }
     424              : 
     425              : /*
     426              :  * Initialize compression filter
     427              :  */
     428              : static int
     429            3 : init_compress(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
     430              : {
     431              :     int         res;
     432            3 :     uint8       type = ctx->compress_algo;
     433              :     PushFilter *pkt;
     434              : 
     435            3 :     res = write_tag_only(dst, PGP_PKT_COMPRESSED_DATA);
     436            3 :     if (res < 0)
     437            0 :         return res;
     438              : 
     439            3 :     res = pushf_create(&pkt, &pkt_stream_filter, ctx, dst);
     440            3 :     if (res < 0)
     441            0 :         return res;
     442              : 
     443            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)
     448            0 :         pushf_free(pkt);
     449              : 
     450            3 :     return res;
     451              : }
     452              : 
     453              : /*
     454              :  * Initialize encdata packet
     455              :  */
     456              : static int
     457           36 : init_encdata_packet(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
     458              : {
     459              :     int         res;
     460              :     int         tag;
     461              : 
     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)
     469            0 :         return res;
     470              : 
     471           36 :     return pushf_create(pf_res, &pkt_stream_filter, ctx, dst);
     472              : }
     473              : 
     474              : /*
     475              :  * write prefix
     476              :  */
     477              : static int
     478           36 : write_prefix(PGP_Context *ctx, PushFilter *dst)
     479              : {
     480              :     uint8       prefix[PGP_MAX_BLOCK + 2];
     481              :     int         res,
     482              :                 bs;
     483              : 
     484           36 :     bs = pgp_get_cipher_block_size(ctx->cipher_algo);
     485           36 :     if (!pg_strong_random(prefix, bs))
     486            0 :         return PXE_NO_RANDOM;
     487              : 
     488           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);
     492           36 :     px_memset(prefix, 0, bs + 2);
     493           36 :     return res < 0 ? res : 0;
     494              : }
     495              : 
     496              : /*
     497              :  * write symmetrically encrypted session key packet
     498              :  */
     499              : 
     500              : static int
     501            4 : symencrypt_sesskey(PGP_Context *ctx, uint8 *dst)
     502              : {
     503              :     int         res;
     504              :     PGP_CFB    *cfb;
     505            4 :     uint8       algo = ctx->cipher_algo;
     506              : 
     507            4 :     res = pgp_cfb_create(&cfb, ctx->s2k_cipher_algo,
     508            4 :                          ctx->s2k.key, ctx->s2k.key_len, 0, NULL);
     509            4 :     if (res < 0)
     510            0 :         return res;
     511              : 
     512            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
     521           30 : write_symenc_sesskey(PGP_Context *ctx, PushFilter *dst)
     522              : {
     523              :     uint8       pkt[256];
     524              :     int         pktlen;
     525              :     int         res;
     526           30 :     uint8      *p = pkt;
     527              : 
     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)
     545            0 :             return res;
     546            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              : 
     554           30 :     px_memset(pkt, 0, pktlen);
     555           30 :     return res;
     556              : }
     557              : 
     558              : /*
     559              :  * key setup
     560              :  */
     561              : static int
     562           30 : init_s2k_key(PGP_Context *ctx)
     563              : {
     564              :     int         res;
     565              : 
     566           30 :     if (ctx->s2k_cipher_algo < 0)
     567           30 :         ctx->s2k_cipher_algo = ctx->cipher_algo;
     568              : 
     569           30 :     res = pgp_s2k_fill(&ctx->s2k, ctx->s2k_mode, ctx->s2k_digest_algo, ctx->s2k_count);
     570           30 :     if (res < 0)
     571            0 :         return res;
     572              : 
     573           30 :     return pgp_s2k_process(&ctx->s2k, ctx->s2k_cipher_algo,
     574              :                            ctx->sym_key, ctx->sym_key_len);
     575              : }
     576              : 
     577              : static int
     578           36 : init_sess_key(PGP_Context *ctx)
     579              : {
     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);
     583           10 :         if (!pg_strong_random(ctx->sess_key, ctx->sess_key_len))
     584            0 :             return PXE_NO_RANDOM;
     585              :     }
     586              :     else
     587              :     {
     588           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
     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              :      */
     610           36 :     if (!ctx->sym_key && !ctx->pub_key)
     611            0 :         return PXE_ARGUMENT_ERROR;
     612              : 
     613              :     /* MBuf writer */
     614           36 :     res = pushf_create_mbuf_writer(&pf, dst);
     615           36 :     if (res < 0)
     616            0 :         goto out;
     617              : 
     618              :     /*
     619              :      * initialize sym_key
     620              :      */
     621           36 :     if (ctx->sym_key)
     622              :     {
     623           30 :         res = init_s2k_key(ctx);
     624           30 :         if (res < 0)
     625            0 :             goto out;
     626              :     }
     627              : 
     628           36 :     res = init_sess_key(ctx);
     629           36 :     if (res < 0)
     630            0 :         goto out;
     631              : 
     632              :     /*
     633              :      * write keypkt
     634              :      */
     635           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)
     640            0 :         goto out;
     641              : 
     642              :     /* encrypted data pkt */
     643           36 :     res = init_encdata_packet(&pf_tmp, ctx, pf);
     644           36 :     if (res < 0)
     645            0 :         goto out;
     646           36 :     pf = pf_tmp;
     647              : 
     648              :     /* encrypter */
     649           36 :     res = pushf_create(&pf_tmp, &encrypt_filter, ctx, pf);
     650           36 :     if (res < 0)
     651            0 :         goto out;
     652           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)
     659            0 :             goto out;
     660           35 :         pf = pf_tmp;
     661              :     }
     662              : 
     663              :     /* prefix */
     664           36 :     res = write_prefix(ctx, pf);
     665           36 :     if (res < 0)
     666            0 :         goto out;
     667              : 
     668              :     /* compressor */
     669           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)
     673            0 :             goto out;
     674            3 :         pf = pf_tmp;
     675              :     }
     676              : 
     677              :     /* data streamer */
     678           36 :     res = init_litdata_packet(&pf_tmp, ctx, pf);
     679           36 :     if (res < 0)
     680            0 :         goto out;
     681           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)
     689            0 :             goto out;
     690            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);
     701            0 : out:
     702           36 :     pushf_free_all(pf);
     703           36 :     return res;
     704              : }
        

Generated by: LCOV version 2.0-1