LCOV - code coverage report
Current view: top level - contrib/pgcrypto - pgp-decrypt.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 80.1 % 558 447
Test Date: 2026-07-03 19:57:34 Functions: 100.0 % 31 31
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 64.4 % 320 206

             Branch data     Line data    Source code
       1                 :             : /*
       2                 :             :  * pgp-decrypt.c
       3                 :             :  *    OpenPGP decrypt.
       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-decrypt.c
      30                 :             :  */
      31                 :             : 
      32                 :             : #include "postgres.h"
      33                 :             : 
      34                 :             : #include "mbuf.h"
      35                 :             : #include "pgp.h"
      36                 :             : #include "px.h"
      37                 :             : 
      38                 :             : #define NO_CTX_SIZE     0
      39                 :             : #define ALLOW_CTX_SIZE  1
      40                 :             : #define NO_COMPR        0
      41                 :             : #define ALLOW_COMPR     1
      42                 :             : #define NO_MDC          0
      43                 :             : #define NEED_MDC        1
      44                 :             : 
      45                 :             : #define PKT_NORMAL 1
      46                 :             : #define PKT_STREAM 2
      47                 :             : #define PKT_CONTEXT 3
      48                 :             : 
      49                 :             : #define MAX_CHUNK (16*1024*1024)
      50                 :             : 
      51                 :             : static int
      52                 :         273 : parse_new_len(PullFilter *src, int *len_p)
      53                 :             : {
      54                 :             :     uint8       b;
      55                 :             :     int         len;
      56                 :         273 :     int         pkttype = PKT_NORMAL;
      57                 :             : 
      58         [ -  + ]:         273 :     GETBYTE(src, b);
      59         [ +  + ]:         273 :     if (b <= 191)
      60                 :         247 :         len = b;
      61   [ +  -  +  + ]:          26 :     else if (b >= 192 && b <= 223)
      62                 :             :     {
      63                 :          10 :         len = ((unsigned) (b) - 192) << 8;
      64         [ -  + ]:          10 :         GETBYTE(src, b);
      65                 :          10 :         len += 192 + b;
      66                 :             :     }
      67         [ +  + ]:          16 :     else if (b == 255)
      68                 :             :     {
      69         [ -  + ]:           1 :         GETBYTE(src, b);
      70                 :           1 :         len = b;
      71         [ -  + ]:           1 :         GETBYTE(src, b);
      72                 :           1 :         len = (len << 8) | b;
      73         [ -  + ]:           1 :         GETBYTE(src, b);
      74                 :           1 :         len = (len << 8) | b;
      75         [ -  + ]:           1 :         GETBYTE(src, b);
      76                 :           1 :         len = (len << 8) | b;
      77                 :             :     }
      78                 :             :     else
      79                 :             :     {
      80                 :          15 :         len = 1 << (b & 0x1F);
      81                 :          15 :         pkttype = PKT_STREAM;
      82                 :             :     }
      83                 :             : 
      84   [ +  -  -  + ]:         273 :     if (len < 0 || len > MAX_CHUNK)
      85                 :             :     {
      86                 :           0 :         px_debug("parse_new_len: weird length");
      87                 :           0 :         return PXE_PGP_CORRUPT_DATA;
      88                 :             :     }
      89                 :             : 
      90                 :         273 :     *len_p = len;
      91                 :         273 :     return pkttype;
      92                 :             : }
      93                 :             : 
      94                 :             : static int
      95                 :         214 : parse_old_len(PullFilter *src, int *len_p, int lentype)
      96                 :             : {
      97                 :             :     uint8       b;
      98                 :             :     int         len;
      99                 :             : 
     100         [ -  + ]:         214 :     GETBYTE(src, b);
     101                 :         214 :     len = b;
     102                 :             : 
     103         [ +  + ]:         214 :     if (lentype == 1)
     104                 :             :     {
     105         [ -  + ]:         102 :         GETBYTE(src, b);
     106                 :         102 :         len = (len << 8) | b;
     107                 :             :     }
     108         [ -  + ]:         112 :     else if (lentype == 2)
     109                 :             :     {
     110         [ #  # ]:           0 :         GETBYTE(src, b);
     111                 :           0 :         len = (len << 8) | b;
     112         [ #  # ]:           0 :         GETBYTE(src, b);
     113                 :           0 :         len = (len << 8) | b;
     114         [ #  # ]:           0 :         GETBYTE(src, b);
     115                 :           0 :         len = (len << 8) | b;
     116                 :             :     }
     117                 :             : 
     118   [ +  -  -  + ]:         214 :     if (len < 0 || len > MAX_CHUNK)
     119                 :             :     {
     120                 :           0 :         px_debug("parse_old_len: weird length");
     121                 :           0 :         return PXE_PGP_CORRUPT_DATA;
     122                 :             :     }
     123                 :         214 :     *len_p = len;
     124                 :         214 :     return PKT_NORMAL;
     125                 :             : }
     126                 :             : 
     127                 :             : /* returns pkttype or 0 on eof */
     128                 :             : int
     129                 :         654 : pgp_parse_pkt_hdr(PullFilter *src, uint8 *tag, int *len_p, int allow_ctx)
     130                 :             : {
     131                 :             :     int         lentype;
     132                 :             :     int         res;
     133                 :             :     uint8      *p;
     134                 :             : 
     135                 :             :     /* EOF is normal here, thus we don't use GETBYTE */
     136                 :         654 :     res = pullf_read(src, 1, &p);
     137         [ -  + ]:         654 :     if (res < 0)
     138                 :           0 :         return res;
     139         [ +  + ]:         654 :     if (res == 0)
     140                 :         175 :         return 0;
     141                 :             : 
     142         [ +  + ]:         479 :     if ((*p & 0x80) == 0)
     143                 :             :     {
     144                 :           2 :         px_debug("pgp_parse_pkt_hdr: not pkt hdr");
     145                 :           2 :         return PXE_PGP_CORRUPT_DATA;
     146                 :             :     }
     147                 :             : 
     148         [ +  + ]:         477 :     if (*p & 0x40)
     149                 :             :     {
     150                 :         260 :         *tag = *p & 0x3f;
     151                 :         260 :         res = parse_new_len(src, len_p);
     152                 :             :     }
     153                 :             :     else
     154                 :             :     {
     155                 :         217 :         lentype = *p & 3;
     156                 :         217 :         *tag = (*p >> 2) & 0x0F;
     157         [ +  + ]:         217 :         if (lentype == 3)
     158         [ +  - ]:           3 :             res = allow_ctx ? PKT_CONTEXT : PXE_PGP_CORRUPT_DATA;
     159                 :             :         else
     160                 :         214 :             res = parse_old_len(src, len_p, lentype);
     161                 :             :     }
     162                 :         477 :     return res;
     163                 :             : }
     164                 :             : 
     165                 :             : /*
     166                 :             :  * Packet reader
     167                 :             :  */
     168                 :             : struct PktData
     169                 :             : {
     170                 :             :     int         type;
     171                 :             :     int         len;
     172                 :             : };
     173                 :             : 
     174                 :             : static int
     175                 :        2590 : pktreader_pull(void *priv, PullFilter *src, int len,
     176                 :             :                uint8 **data_p, uint8 *buf, int buflen)
     177                 :             : {
     178                 :             :     int         res;
     179                 :        2590 :     struct PktData *pkt = priv;
     180                 :             : 
     181                 :             :     /* PKT_CONTEXT means: whatever there is */
     182         [ -  + ]:        2590 :     if (pkt->type == PKT_CONTEXT)
     183                 :           0 :         return pullf_read(src, len, data_p);
     184                 :             : 
     185         [ +  + ]:        2603 :     while (pkt->len == 0)
     186                 :             :     {
     187                 :             :         /* this was last chunk in stream */
     188         [ +  + ]:         404 :         if (pkt->type == PKT_NORMAL)
     189                 :         391 :             return 0;
     190                 :             : 
     191                 :             :         /* next chunk in stream */
     192                 :          13 :         res = parse_new_len(src, &pkt->len);
     193         [ -  + ]:          13 :         if (res < 0)
     194                 :           0 :             return res;
     195                 :          13 :         pkt->type = res;
     196                 :             :     }
     197                 :             : 
     198         [ +  + ]:        2199 :     if (len > pkt->len)
     199                 :         264 :         len = pkt->len;
     200                 :             : 
     201                 :        2199 :     res = pullf_read(src, len, data_p);
     202         [ +  - ]:        2199 :     if (res > 0)
     203                 :        2199 :         pkt->len -= res;
     204                 :             : 
     205                 :        2199 :     return res;
     206                 :             : }
     207                 :             : 
     208                 :             : static void
     209                 :         474 : pktreader_free(void *priv)
     210                 :             : {
     211                 :         474 :     struct PktData *pkt = priv;
     212                 :             : 
     213                 :         474 :     px_memset(pkt, 0, sizeof(*pkt));
     214                 :         474 :     pfree(pkt);
     215                 :         474 : }
     216                 :             : 
     217                 :             : static struct PullFilterOps pktreader_filter = {
     218                 :             :     NULL, pktreader_pull, pktreader_free
     219                 :             : };
     220                 :             : 
     221                 :             : /* needs helper function to pass several parameters */
     222                 :             : int
     223                 :         474 : pgp_create_pkt_reader(PullFilter **pf_p, PullFilter *src, int len,
     224                 :             :                       int pkttype, PGP_Context *ctx)
     225                 :             : {
     226                 :             :     int         res;
     227                 :         474 :     struct PktData *pkt = palloc_object(struct PktData);
     228                 :             : 
     229                 :         474 :     pkt->type = pkttype;
     230                 :         474 :     pkt->len = len;
     231                 :         474 :     res = pullf_create(pf_p, &pktreader_filter, pkt, src);
     232         [ -  + ]:         474 :     if (res < 0)
     233                 :           0 :         pfree(pkt);
     234                 :         474 :     return res;
     235                 :             : }
     236                 :             : 
     237                 :             : /*
     238                 :             :  * Prefix check filter
     239                 :             :  * https://tools.ietf.org/html/rfc4880#section-5.7
     240                 :             :  * https://tools.ietf.org/html/rfc4880#section-5.13
     241                 :             :  */
     242                 :             : 
     243                 :             : static int
     244                 :          73 : prefix_init(void **priv_p, void *arg, PullFilter *src)
     245                 :             : {
     246                 :          73 :     PGP_Context *ctx = arg;
     247                 :             :     int         len;
     248                 :             :     int         res;
     249                 :             :     uint8      *buf;
     250                 :             :     uint8       tmpbuf[PGP_MAX_BLOCK + 2];
     251                 :             : 
     252                 :          73 :     len = pgp_get_cipher_block_size(ctx->cipher_algo);
     253                 :             :     /* Make sure we have space for prefix */
     254         [ -  + ]:          73 :     if (len > PGP_MAX_BLOCK)
     255                 :           0 :         return PXE_BUG;
     256                 :             : 
     257                 :          73 :     res = pullf_read_max(src, len + 2, &buf, tmpbuf);
     258         [ -  + ]:          73 :     if (res < 0)
     259                 :           0 :         return res;
     260         [ -  + ]:          73 :     if (res != len + 2)
     261                 :             :     {
     262                 :           0 :         px_debug("prefix_init: short read");
     263                 :           0 :         px_memset(tmpbuf, 0, sizeof(tmpbuf));
     264                 :           0 :         return PXE_PGP_CORRUPT_DATA;
     265                 :             :     }
     266                 :             : 
     267   [ +  +  -  + ]:          73 :     if (buf[len - 2] != buf[len] || buf[len - 1] != buf[len + 1])
     268                 :             :     {
     269                 :           4 :         px_debug("prefix_init: corrupt prefix");
     270                 :             :         /* report error in pgp_decrypt() */
     271                 :           4 :         ctx->corrupt_prefix = 1;
     272                 :             :     }
     273                 :          73 :     px_memset(tmpbuf, 0, sizeof(tmpbuf));
     274                 :          73 :     return 0;
     275                 :             : }
     276                 :             : 
     277                 :             : static struct PullFilterOps prefix_filter = {
     278                 :             :     prefix_init, NULL, NULL
     279                 :             : };
     280                 :             : 
     281                 :             : 
     282                 :             : /*
     283                 :             :  * Decrypt filter
     284                 :             :  */
     285                 :             : 
     286                 :             : static int
     287                 :          77 : decrypt_init(void **priv_p, void *arg, PullFilter *src)
     288                 :             : {
     289                 :          77 :     PGP_CFB    *cfb = arg;
     290                 :             : 
     291                 :          77 :     *priv_p = cfb;
     292                 :             : 
     293                 :             :     /* we need to write somewhere, so ask for a buffer */
     294                 :          77 :     return 4096;
     295                 :             : }
     296                 :             : 
     297                 :             : static int
     298                 :         815 : decrypt_read(void *priv, PullFilter *src, int len,
     299                 :             :              uint8 **data_p, uint8 *buf, int buflen)
     300                 :             : {
     301                 :         815 :     PGP_CFB    *cfb = priv;
     302                 :             :     uint8      *tmp;
     303                 :             :     int         res;
     304                 :             : 
     305                 :         815 :     res = pullf_read(src, len, &tmp);
     306         [ +  + ]:         815 :     if (res > 0)
     307                 :             :     {
     308                 :         740 :         pgp_cfb_decrypt(cfb, tmp, res, buf);
     309                 :         740 :         *data_p = buf;
     310                 :             :     }
     311                 :         815 :     return res;
     312                 :             : }
     313                 :             : 
     314                 :             : struct PullFilterOps pgp_decrypt_filter = {
     315                 :             :     decrypt_init, decrypt_read, NULL
     316                 :             : };
     317                 :             : 
     318                 :             : 
     319                 :             : /*
     320                 :             :  * MDC hasher filter
     321                 :             :  */
     322                 :             : 
     323                 :             : static int
     324                 :          71 : mdc_init(void **priv_p, void *arg, PullFilter *src)
     325                 :             : {
     326                 :          71 :     PGP_Context *ctx = arg;
     327                 :             : 
     328                 :          71 :     *priv_p = ctx;
     329                 :          71 :     return pgp_load_digest(PGP_DIGEST_SHA1, &ctx->mdc_ctx);
     330                 :             : }
     331                 :             : 
     332                 :             : static void
     333                 :          71 : mdc_free(void *priv)
     334                 :             : {
     335                 :          71 :     PGP_Context *ctx = priv;
     336                 :             : 
     337         [ +  + ]:          71 :     if (ctx->use_mdcbuf_filter)
     338                 :           3 :         return;
     339                 :          68 :     px_md_free(ctx->mdc_ctx);
     340                 :          68 :     ctx->mdc_ctx = NULL;
     341                 :             : }
     342                 :             : 
     343                 :             : static int
     344                 :          65 : mdc_finish(PGP_Context *ctx, PullFilter *src, int len)
     345                 :             : {
     346                 :             :     int         res;
     347                 :             :     uint8       hash[20];
     348                 :             :     uint8       tmpbuf[20];
     349                 :             :     uint8      *data;
     350                 :             : 
     351                 :             :     /* should not happen */
     352         [ -  + ]:          65 :     if (ctx->use_mdcbuf_filter)
     353                 :           0 :         return PXE_BUG;
     354                 :             : 
     355                 :             :     /* It's SHA1 */
     356         [ -  + ]:          65 :     if (len != 20)
     357                 :           0 :         return PXE_PGP_CORRUPT_DATA;
     358                 :             : 
     359                 :             :     /* mdc_read should not call px_md_update */
     360                 :          65 :     ctx->in_mdc_pkt = 1;
     361                 :             : 
     362                 :             :     /* read data */
     363                 :          65 :     res = pullf_read_max(src, len, &data, tmpbuf);
     364         [ -  + ]:          65 :     if (res < 0)
     365                 :           0 :         return res;
     366         [ -  + ]:          65 :     if (res == 0)
     367                 :             :     {
     368                 :           0 :         px_debug("no mdc");
     369                 :           0 :         return PXE_PGP_CORRUPT_DATA;
     370                 :             :     }
     371                 :             : 
     372                 :             :     /* is the packet sane? */
     373         [ -  + ]:          65 :     if (res != 20)
     374                 :             :     {
     375                 :           0 :         px_debug("mdc_finish: read failed, res=%d", res);
     376                 :           0 :         return PXE_PGP_CORRUPT_DATA;
     377                 :             :     }
     378                 :             : 
     379                 :             :     /*
     380                 :             :      * ok, we got the hash, now check
     381                 :             :      */
     382                 :          65 :     px_md_finish(ctx->mdc_ctx, hash);
     383                 :          65 :     res = memcmp(hash, data, 20);
     384                 :          65 :     px_memset(hash, 0, 20);
     385                 :          65 :     px_memset(tmpbuf, 0, sizeof(tmpbuf));
     386         [ -  + ]:          65 :     if (res != 0)
     387                 :             :     {
     388                 :           0 :         px_debug("mdc_finish: mdc failed");
     389                 :           0 :         return PXE_PGP_CORRUPT_DATA;
     390                 :             :     }
     391                 :          65 :     ctx->mdc_checked = 1;
     392                 :          65 :     return 0;
     393                 :             : }
     394                 :             : 
     395                 :             : static int
     396                 :         776 : mdc_read(void *priv, PullFilter *src, int len,
     397                 :             :          uint8 **data_p, uint8 *buf, int buflen)
     398                 :             : {
     399                 :             :     int         res;
     400                 :         776 :     PGP_Context *ctx = priv;
     401                 :             : 
     402                 :             :     /* skip this filter? */
     403   [ +  +  +  + ]:         776 :     if (ctx->use_mdcbuf_filter || ctx->in_mdc_pkt)
     404                 :         137 :         return pullf_read(src, len, data_p);
     405                 :             : 
     406                 :         639 :     res = pullf_read(src, len, data_p);
     407         [ -  + ]:         639 :     if (res < 0)
     408                 :           0 :         return res;
     409         [ -  + ]:         639 :     if (res == 0)
     410                 :             :     {
     411                 :           0 :         px_debug("mdc_read: unexpected eof");
     412                 :           0 :         return PXE_PGP_CORRUPT_DATA;
     413                 :             :     }
     414                 :         639 :     px_md_update(ctx->mdc_ctx, *data_p, res);
     415                 :             : 
     416                 :         639 :     return res;
     417                 :             : }
     418                 :             : 
     419                 :             : static struct PullFilterOps mdc_filter = {
     420                 :             :     mdc_init, mdc_read, mdc_free
     421                 :             : };
     422                 :             : 
     423                 :             : 
     424                 :             : /*
     425                 :             :  * Combined Pkt reader and MDC hasher.
     426                 :             :  *
     427                 :             :  * For the case of SYMENCRYPTED_DATA_MDC packet, where
     428                 :             :  * the data part has 'context length', which means
     429                 :             :  * that data packet ends 22 bytes before end of parent
     430                 :             :  * packet, which is silly.
     431                 :             :  */
     432                 :             : #define MDCBUF_LEN 8192
     433                 :             : struct MDCBufData
     434                 :             : {
     435                 :             :     PGP_Context *ctx;
     436                 :             :     int         eof;
     437                 :             :     int         buflen;
     438                 :             :     int         avail;
     439                 :             :     uint8      *pos;
     440                 :             :     int         mdc_avail;
     441                 :             :     uint8       mdc_buf[22];
     442                 :             :     uint8       buf[MDCBUF_LEN];
     443                 :             : };
     444                 :             : 
     445                 :             : static int
     446                 :           3 : mdcbuf_init(void **priv_p, void *arg, PullFilter *src)
     447                 :             : {
     448                 :           3 :     PGP_Context *ctx = arg;
     449                 :             :     struct MDCBufData *st;
     450                 :             : 
     451                 :           3 :     st = palloc0_object(struct MDCBufData);
     452                 :           3 :     st->buflen = sizeof(st->buf);
     453                 :           3 :     st->ctx = ctx;
     454                 :           3 :     *priv_p = st;
     455                 :             : 
     456                 :             :     /* take over the work of mdc_filter */
     457                 :           3 :     ctx->use_mdcbuf_filter = 1;
     458                 :             : 
     459                 :           3 :     return 0;
     460                 :             : }
     461                 :             : 
     462                 :             : static int
     463                 :           3 : mdcbuf_finish(struct MDCBufData *st)
     464                 :             : {
     465                 :             :     uint8       hash[20];
     466                 :             :     int         res;
     467                 :             : 
     468                 :           3 :     st->eof = 1;
     469                 :             : 
     470   [ +  +  -  + ]:           3 :     if (st->mdc_buf[0] != 0xD3 || st->mdc_buf[1] != 0x14)
     471                 :             :     {
     472                 :           2 :         px_debug("mdcbuf_finish: bad MDC pkt hdr");
     473                 :           2 :         return PXE_PGP_CORRUPT_DATA;
     474                 :             :     }
     475                 :           1 :     px_md_update(st->ctx->mdc_ctx, st->mdc_buf, 2);
     476                 :           1 :     px_md_finish(st->ctx->mdc_ctx, hash);
     477                 :           1 :     res = memcmp(hash, st->mdc_buf + 2, 20);
     478                 :           1 :     px_memset(hash, 0, 20);
     479         [ -  + ]:           1 :     if (res)
     480                 :             :     {
     481                 :           0 :         px_debug("mdcbuf_finish: MDC does not match");
     482                 :           0 :         res = PXE_PGP_CORRUPT_DATA;
     483                 :             :     }
     484                 :           1 :     return res;
     485                 :             : }
     486                 :             : 
     487                 :             : static void
     488                 :           6 : mdcbuf_load_data(struct MDCBufData *st, uint8 *src, int len)
     489                 :             : {
     490                 :           6 :     uint8      *dst = st->pos + st->avail;
     491                 :             : 
     492                 :           6 :     memcpy(dst, src, len);
     493                 :           6 :     px_md_update(st->ctx->mdc_ctx, src, len);
     494                 :           6 :     st->avail += len;
     495                 :           6 : }
     496                 :             : 
     497                 :             : static void
     498                 :           3 : mdcbuf_load_mdc(struct MDCBufData *st, uint8 *src, int len)
     499                 :             : {
     500                 :           3 :     memmove(st->mdc_buf + st->mdc_avail, src, len);
     501                 :           3 :     st->mdc_avail += len;
     502                 :           3 : }
     503                 :             : 
     504                 :             : static int
     505                 :           6 : mdcbuf_refill(struct MDCBufData *st, PullFilter *src)
     506                 :             : {
     507                 :             :     uint8      *data;
     508                 :             :     int         res;
     509                 :             :     int         need;
     510                 :             : 
     511                 :             :     /* put avail data in start */
     512   [ +  +  +  - ]:           6 :     if (st->avail > 0 && st->pos != st->buf)
     513                 :           3 :         memmove(st->buf, st->pos, st->avail);
     514                 :           6 :     st->pos = st->buf;
     515                 :             : 
     516                 :             :     /* read new data */
     517                 :           6 :     need = st->buflen + 22 - st->avail - st->mdc_avail;
     518                 :           6 :     res = pullf_read(src, need, &data);
     519         [ -  + ]:           6 :     if (res < 0)
     520                 :           0 :         return res;
     521         [ +  + ]:           6 :     if (res == 0)
     522                 :           3 :         return mdcbuf_finish(st);
     523                 :             : 
     524                 :             :     /* add to buffer */
     525         [ +  - ]:           3 :     if (res >= 22)
     526                 :             :     {
     527                 :           3 :         mdcbuf_load_data(st, st->mdc_buf, st->mdc_avail);
     528                 :           3 :         st->mdc_avail = 0;
     529                 :             : 
     530                 :           3 :         mdcbuf_load_data(st, data, res - 22);
     531                 :           3 :         mdcbuf_load_mdc(st, data + res - 22, 22);
     532                 :             :     }
     533                 :             :     else
     534                 :             :     {
     535                 :           0 :         int         canmove = st->mdc_avail + res - 22;
     536                 :             : 
     537         [ #  # ]:           0 :         if (canmove > 0)
     538                 :             :         {
     539                 :           0 :             mdcbuf_load_data(st, st->mdc_buf, canmove);
     540                 :           0 :             st->mdc_avail -= canmove;
     541                 :           0 :             memmove(st->mdc_buf, st->mdc_buf + canmove, st->mdc_avail);
     542                 :             :         }
     543                 :           0 :         mdcbuf_load_mdc(st, data, res);
     544                 :             :     }
     545                 :           3 :     return 0;
     546                 :             : }
     547                 :             : 
     548                 :             : static int
     549                 :          10 : mdcbuf_read(void *priv, PullFilter *src, int len,
     550                 :             :             uint8 **data_p, uint8 *buf, int buflen)
     551                 :             : {
     552                 :          10 :     struct MDCBufData *st = priv;
     553                 :             :     int         res;
     554                 :             : 
     555   [ +  +  +  + ]:          10 :     if (!st->eof && len > st->avail)
     556                 :             :     {
     557                 :           6 :         res = mdcbuf_refill(st, src);
     558         [ +  + ]:           6 :         if (res < 0)
     559                 :           2 :             return res;
     560                 :             :     }
     561                 :             : 
     562         [ +  + ]:           8 :     if (len > st->avail)
     563                 :           2 :         len = st->avail;
     564                 :             : 
     565                 :           8 :     *data_p = st->pos;
     566                 :           8 :     st->pos += len;
     567                 :           8 :     st->avail -= len;
     568                 :           8 :     return len;
     569                 :             : }
     570                 :             : 
     571                 :             : static void
     572                 :           3 : mdcbuf_free(void *priv)
     573                 :             : {
     574                 :           3 :     struct MDCBufData *st = priv;
     575                 :             : 
     576                 :           3 :     px_md_free(st->ctx->mdc_ctx);
     577                 :           3 :     st->ctx->mdc_ctx = NULL;
     578                 :           3 :     px_memset(st, 0, sizeof(*st));
     579                 :           3 :     pfree(st);
     580                 :           3 : }
     581                 :             : 
     582                 :             : static struct PullFilterOps mdcbuf_filter = {
     583                 :             :     mdcbuf_init, mdcbuf_read, mdcbuf_free
     584                 :             : };
     585                 :             : 
     586                 :             : 
     587                 :             : /*
     588                 :             :  * Decrypt separate session key
     589                 :             :  */
     590                 :             : static int
     591                 :           4 : decrypt_key(PGP_Context *ctx, const uint8 *src, int len)
     592                 :             : {
     593                 :             :     int         res;
     594                 :             :     uint8       algo;
     595                 :             :     PGP_CFB    *cfb;
     596                 :             : 
     597                 :           4 :     res = pgp_cfb_create(&cfb, ctx->s2k_cipher_algo,
     598                 :           4 :                          ctx->s2k.key, ctx->s2k.key_len, 0, NULL);
     599         [ -  + ]:           4 :     if (res < 0)
     600                 :           0 :         return res;
     601                 :             : 
     602                 :           4 :     pgp_cfb_decrypt(cfb, src, 1, &algo);
     603                 :           4 :     src++;
     604                 :           4 :     len--;
     605                 :             : 
     606                 :           4 :     pgp_cfb_decrypt(cfb, src, len, ctx->sess_key);
     607                 :           4 :     pgp_cfb_free(cfb);
     608                 :           4 :     ctx->sess_key_len = len;
     609                 :           4 :     ctx->cipher_algo = algo;
     610                 :             : 
     611         [ -  + ]:           4 :     if (pgp_get_cipher_key_size(algo) != len)
     612                 :             :     {
     613                 :           0 :         px_debug("sesskey bad len: algo=%d, expected=%d, got=%d",
     614                 :             :                  algo, pgp_get_cipher_key_size(algo), len);
     615                 :           0 :         return PXE_PGP_CORRUPT_DATA;
     616                 :             :     }
     617                 :           4 :     return 0;
     618                 :             : }
     619                 :             : 
     620                 :             : /*
     621                 :             :  * Handle key packet
     622                 :             :  */
     623                 :             : static int
     624                 :          60 : parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src)
     625                 :             : {
     626                 :             :     uint8      *p;
     627                 :             :     int         res;
     628                 :             :     uint8       tmpbuf[PGP_MAX_KEY + 2];
     629                 :             :     uint8       ver;
     630                 :             : 
     631         [ -  + ]:          60 :     GETBYTE(src, ver);
     632         [ -  + ]:          60 :     GETBYTE(src, ctx->s2k_cipher_algo);
     633         [ -  + ]:          60 :     if (ver != 4)
     634                 :             :     {
     635                 :           0 :         px_debug("bad key pkt ver");
     636                 :           0 :         return PXE_PGP_CORRUPT_DATA;
     637                 :             :     }
     638                 :             : 
     639                 :             :     /*
     640                 :             :      * read S2K info
     641                 :             :      */
     642                 :          60 :     res = pgp_s2k_read(src, &ctx->s2k);
     643         [ -  + ]:          60 :     if (res < 0)
     644                 :           0 :         return res;
     645                 :          60 :     ctx->s2k_mode = ctx->s2k.mode;
     646                 :          60 :     ctx->s2k_count = s2k_decode_count(ctx->s2k.iter);
     647                 :          60 :     ctx->s2k_digest_algo = ctx->s2k.digest_algo;
     648                 :             : 
     649                 :             :     /*
     650                 :             :      * generate key from password
     651                 :             :      */
     652                 :          60 :     res = pgp_s2k_process(&ctx->s2k, ctx->s2k_cipher_algo,
     653                 :             :                           ctx->sym_key, ctx->sym_key_len);
     654         [ -  + ]:          60 :     if (res < 0)
     655                 :           0 :         return res;
     656                 :             : 
     657                 :             :     /*
     658                 :             :      * do we have separate session key?
     659                 :             :      */
     660                 :          60 :     res = pullf_read_max(src, PGP_MAX_KEY + 2, &p, tmpbuf);
     661         [ -  + ]:          60 :     if (res < 0)
     662                 :           0 :         return res;
     663                 :             : 
     664         [ +  + ]:          60 :     if (res == 0)
     665                 :             :     {
     666                 :             :         /*
     667                 :             :          * no, s2k key is session key
     668                 :             :          */
     669                 :          56 :         memcpy(ctx->sess_key, ctx->s2k.key, ctx->s2k.key_len);
     670                 :          56 :         ctx->sess_key_len = ctx->s2k.key_len;
     671                 :          56 :         ctx->cipher_algo = ctx->s2k_cipher_algo;
     672                 :          56 :         res = 0;
     673                 :          56 :         ctx->use_sess_key = 0;
     674                 :             :     }
     675                 :             :     else
     676                 :             :     {
     677                 :             :         /*
     678                 :             :          * yes, decrypt it
     679                 :             :          */
     680   [ +  -  -  + ]:           4 :         if (res < 17 || res > PGP_MAX_KEY + 1)
     681                 :             :         {
     682                 :           0 :             px_debug("expect key, but bad data");
     683                 :           0 :             return PXE_PGP_CORRUPT_DATA;
     684                 :             :         }
     685                 :           4 :         ctx->use_sess_key = 1;
     686                 :           4 :         res = decrypt_key(ctx, p, res);
     687                 :             :     }
     688                 :             : 
     689                 :          60 :     px_memset(tmpbuf, 0, sizeof(tmpbuf));
     690                 :          60 :     return res;
     691                 :             : }
     692                 :             : 
     693                 :             : static int
     694                 :           2 : copy_crlf(MBuf *dst, uint8 *data, int len, int *got_cr)
     695                 :             : {
     696                 :           2 :     uint8      *data_end = data + len;
     697                 :             :     uint8       tmpbuf[1024];
     698                 :           2 :     uint8      *tmp_end = tmpbuf + sizeof(tmpbuf);
     699                 :             :     uint8      *p;
     700                 :             :     int         res;
     701                 :             : 
     702                 :           2 :     p = tmpbuf;
     703         [ -  + ]:           2 :     if (*got_cr)
     704                 :             :     {
     705         [ #  # ]:           0 :         if (*data != '\n')
     706                 :           0 :             *p++ = '\r';
     707                 :           0 :         *got_cr = 0;
     708                 :             :     }
     709         [ +  - ]:          47 :     while (data < data_end)
     710                 :             :     {
     711         [ +  + ]:          47 :         if (*data == '\r')
     712                 :             :         {
     713         [ +  + ]:          14 :             if (data + 1 < data_end)
     714                 :             :             {
     715         [ +  + ]:          12 :                 if (*(data + 1) == '\n')
     716                 :           7 :                     data++;
     717                 :             :             }
     718                 :             :             else
     719                 :             :             {
     720                 :           2 :                 *got_cr = 1;
     721                 :           2 :                 break;
     722                 :             :             }
     723                 :             :         }
     724                 :          45 :         *p++ = *data++;
     725         [ -  + ]:          45 :         if (p >= tmp_end)
     726                 :             :         {
     727                 :           0 :             res = mbuf_append(dst, tmpbuf, p - tmpbuf);
     728         [ #  # ]:           0 :             if (res < 0)
     729                 :           0 :                 return res;
     730                 :           0 :             p = tmpbuf;
     731                 :             :         }
     732                 :             :     }
     733         [ +  - ]:           2 :     if (p - tmpbuf > 0)
     734                 :             :     {
     735                 :           2 :         res = mbuf_append(dst, tmpbuf, p - tmpbuf);
     736         [ -  + ]:           2 :         if (res < 0)
     737                 :           0 :             return res;
     738                 :             :     }
     739                 :           2 :     px_memset(tmpbuf, 0, sizeof(tmpbuf));
     740                 :           2 :     return 0;
     741                 :             : }
     742                 :             : 
     743                 :             : static int
     744                 :          68 : parse_literal_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
     745                 :             : {
     746                 :             :     int         type;
     747                 :             :     int         name_len;
     748                 :             :     int         res;
     749                 :             :     uint8      *buf;
     750                 :             :     uint8       tmpbuf[4];
     751                 :          68 :     int         got_cr = 0;
     752                 :             : 
     753         [ -  + ]:          68 :     GETBYTE(pkt, type);
     754         [ -  + ]:          68 :     GETBYTE(pkt, name_len);
     755                 :             : 
     756                 :             :     /* skip name */
     757         [ +  + ]:          91 :     while (name_len > 0)
     758                 :             :     {
     759                 :          23 :         res = pullf_read(pkt, name_len, &buf);
     760         [ -  + ]:          23 :         if (res < 0)
     761                 :           0 :             return res;
     762         [ -  + ]:          23 :         if (res == 0)
     763                 :           0 :             break;
     764                 :          23 :         name_len -= res;
     765                 :             :     }
     766         [ -  + ]:          68 :     if (name_len > 0)
     767                 :             :     {
     768                 :           0 :         px_debug("parse_literal_data: unexpected eof");
     769                 :           0 :         return PXE_PGP_CORRUPT_DATA;
     770                 :             :     }
     771                 :             : 
     772                 :             :     /* skip date */
     773                 :          68 :     res = pullf_read_max(pkt, 4, &buf, tmpbuf);
     774         [ -  + ]:          68 :     if (res != 4)
     775                 :             :     {
     776                 :           0 :         px_debug("parse_literal_data: unexpected eof");
     777                 :           0 :         return PXE_PGP_CORRUPT_DATA;
     778                 :             :     }
     779                 :          68 :     px_memset(tmpbuf, 0, 4);
     780                 :             : 
     781                 :             :     /*
     782                 :             :      * If called from an SQL function that returns text, pgp_decrypt() rejects
     783                 :             :      * inputs not self-identifying as text.
     784                 :             :      */
     785         [ +  + ]:          68 :     if (ctx->text_mode)
     786   [ +  +  +  - ]:          63 :         if (type != 't' && type != 'u')
     787                 :             :         {
     788                 :           4 :             px_debug("parse_literal_data: data type=%c", type);
     789                 :           4 :             ctx->unexpected_binary = true;
     790                 :             :         }
     791                 :             : 
     792                 :          68 :     ctx->unicode_mode = (type == 'u') ? 1 : 0;
     793                 :             : 
     794                 :             :     /* read data */
     795                 :             :     while (1)
     796                 :             :     {
     797                 :         157 :         res = pullf_read(pkt, 32 * 1024, &buf);
     798         [ +  + ]:         157 :         if (res <= 0)
     799                 :          68 :             break;
     800                 :             : 
     801   [ +  +  +  + ]:          89 :         if (ctx->text_mode && ctx->convert_crlf)
     802                 :           2 :             res = copy_crlf(dst, buf, res, &got_cr);
     803                 :             :         else
     804                 :          87 :             res = mbuf_append(dst, buf, res);
     805         [ -  + ]:          89 :         if (res < 0)
     806                 :           0 :             break;
     807                 :             :     }
     808   [ +  +  +  + ]:          68 :     if (res >= 0 && got_cr)
     809                 :           2 :         res = mbuf_append(dst, (const uint8 *) "\r", 1);
     810                 :          68 :     return res;
     811                 :             : }
     812                 :             : 
     813                 :             : /* process_data_packets and parse_compressed_data call each other */
     814                 :             : static int  process_data_packets(PGP_Context *ctx, MBuf *dst,
     815                 :             :                                  PullFilter *src, int allow_compr, int need_mdc);
     816                 :             : 
     817                 :             : static int
     818                 :           6 : parse_compressed_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
     819                 :             : {
     820                 :             :     int         res;
     821                 :             :     uint8       type;
     822                 :             :     PullFilter *pf_decompr;
     823                 :             :     uint8      *discard_buf;
     824                 :             : 
     825         [ -  + ]:           6 :     GETBYTE(pkt, type);
     826                 :             : 
     827                 :           6 :     ctx->compress_algo = type;
     828   [ -  +  +  - ]:           6 :     switch (type)
     829                 :             :     {
     830                 :           0 :         case PGP_COMPR_NONE:
     831                 :           0 :             res = process_data_packets(ctx, dst, pkt, NO_COMPR, NO_MDC);
     832                 :           0 :             break;
     833                 :             : 
     834                 :           4 :         case PGP_COMPR_ZIP:
     835                 :             :         case PGP_COMPR_ZLIB:
     836                 :           4 :             res = pgp_decompress_filter(&pf_decompr, ctx, pkt);
     837         [ +  - ]:           4 :             if (res >= 0)
     838                 :             :             {
     839                 :           4 :                 res = process_data_packets(ctx, dst, pf_decompr,
     840                 :             :                                            NO_COMPR, NO_MDC);
     841                 :           4 :                 pullf_free(pf_decompr);
     842                 :             :             }
     843                 :           4 :             break;
     844                 :             : 
     845                 :           2 :         case PGP_COMPR_BZIP2:
     846                 :           2 :             px_debug("parse_compressed_data: bzip2 unsupported");
     847                 :             :             /* report error in pgp_decrypt() */
     848                 :           2 :             ctx->unsupported_compr = 1;
     849                 :             : 
     850                 :             :             /*
     851                 :             :              * Discard the compressed data, allowing it to first affect any
     852                 :             :              * MDC digest computation.
     853                 :             :              */
     854                 :             :             while (1)
     855                 :             :             {
     856                 :           3 :                 res = pullf_read(pkt, 32 * 1024, &discard_buf);
     857         [ +  + ]:           3 :                 if (res <= 0)
     858                 :           2 :                     break;
     859                 :             :             }
     860                 :             : 
     861                 :           2 :             break;
     862                 :             : 
     863                 :           0 :         default:
     864                 :           0 :             px_debug("parse_compressed_data: unknown compr type");
     865                 :           0 :             res = PXE_PGP_CORRUPT_DATA;
     866                 :             :     }
     867                 :             : 
     868                 :           6 :     return res;
     869                 :             : }
     870                 :             : 
     871                 :             : static int
     872                 :          77 : process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
     873                 :             :                      int allow_compr, int need_mdc)
     874                 :             : {
     875                 :             :     uint8       tag;
     876                 :             :     int         len,
     877                 :             :                 res;
     878                 :          77 :     int         got_data = 0;
     879                 :          77 :     int         got_mdc = 0;
     880                 :          77 :     PullFilter *pkt = NULL;
     881                 :             : 
     882                 :             :     while (1)
     883                 :             :     {
     884                 :         214 :         res = pgp_parse_pkt_hdr(src, &tag, &len, ALLOW_CTX_SIZE);
     885         [ +  + ]:         214 :         if (res <= 0)
     886                 :          74 :             break;
     887                 :             : 
     888                 :             : 
     889                 :             :         /* mdc packet should be last */
     890         [ -  + ]:         140 :         if (got_mdc)
     891                 :             :         {
     892                 :           0 :             px_debug("process_data_packets: data after mdc");
     893                 :           0 :             res = PXE_PGP_CORRUPT_DATA;
     894                 :           0 :             break;
     895                 :             :         }
     896                 :             : 
     897                 :             :         /*
     898                 :             :          * Context length inside SYMENCRYPTED_DATA_MDC packet needs special
     899                 :             :          * handling.
     900                 :             :          */
     901   [ +  +  +  + ]:         140 :         if (need_mdc && res == PKT_CONTEXT)
     902                 :           3 :             res = pullf_create(&pkt, &mdcbuf_filter, ctx, src);
     903                 :             :         else
     904                 :         137 :             res = pgp_create_pkt_reader(&pkt, src, len, res, ctx);
     905         [ -  + ]:         140 :         if (res < 0)
     906                 :           0 :             break;
     907                 :             : 
     908   [ +  +  +  + ]:         140 :         switch (tag)
     909                 :             :         {
     910                 :          68 :             case PGP_PKT_LITERAL_DATA:
     911                 :          68 :                 got_data = 1;
     912                 :          68 :                 res = parse_literal_data(ctx, dst, pkt);
     913                 :          68 :                 break;
     914                 :           6 :             case PGP_PKT_COMPRESSED_DATA:
     915         [ -  + ]:           6 :                 if (allow_compr == 0)
     916                 :             :                 {
     917                 :           0 :                     px_debug("process_data_packets: unexpected compression");
     918                 :           0 :                     res = PXE_PGP_CORRUPT_DATA;
     919                 :             :                 }
     920         [ -  + ]:           6 :                 else if (got_data)
     921                 :             :                 {
     922                 :             :                     /*
     923                 :             :                      * compr data must be alone
     924                 :             :                      */
     925                 :           0 :                     px_debug("process_data_packets: only one cmpr pkt allowed");
     926                 :           0 :                     res = PXE_PGP_CORRUPT_DATA;
     927                 :             :                 }
     928                 :             :                 else
     929                 :             :                 {
     930                 :           6 :                     got_data = 1;
     931                 :           6 :                     res = parse_compressed_data(ctx, dst, pkt);
     932                 :             :                 }
     933                 :           6 :                 break;
     934                 :          65 :             case PGP_PKT_MDC:
     935         [ -  + ]:          65 :                 if (need_mdc == NO_MDC)
     936                 :             :                 {
     937                 :           0 :                     px_debug("process_data_packets: unexpected MDC");
     938                 :           0 :                     res = PXE_PGP_CORRUPT_DATA;
     939                 :           0 :                     break;
     940                 :             :                 }
     941                 :             : 
     942                 :          65 :                 res = mdc_finish(ctx, pkt, len);
     943         [ +  - ]:          65 :                 if (res >= 0)
     944                 :          65 :                     got_mdc = 1;
     945                 :          65 :                 break;
     946                 :           1 :             default:
     947                 :           1 :                 px_debug("process_data_packets: unexpected pkt tag=%d", tag);
     948                 :           1 :                 res = PXE_PGP_CORRUPT_DATA;
     949                 :             :         }
     950                 :             : 
     951                 :         140 :         pullf_free(pkt);
     952                 :         140 :         pkt = NULL;
     953                 :             : 
     954         [ +  + ]:         140 :         if (res < 0)
     955                 :           3 :             break;
     956                 :             :     }
     957                 :             : 
     958         [ -  + ]:          77 :     if (pkt)
     959                 :           0 :         pullf_free(pkt);
     960                 :             : 
     961         [ +  + ]:          77 :     if (res < 0)
     962                 :           5 :         return res;
     963                 :             : 
     964         [ -  + ]:          72 :     if (!got_data)
     965                 :             :     {
     966                 :           0 :         px_debug("process_data_packets: no data");
     967                 :           0 :         res = PXE_PGP_CORRUPT_DATA;
     968                 :             :     }
     969   [ +  +  +  +  :          72 :     if (need_mdc && !got_mdc && !ctx->use_mdcbuf_filter)
                   -  + ]
     970                 :             :     {
     971                 :           0 :         px_debug("process_data_packets: got no mdc");
     972                 :           0 :         res = PXE_PGP_CORRUPT_DATA;
     973                 :             :     }
     974                 :          72 :     return res;
     975                 :             : }
     976                 :             : 
     977                 :             : static int
     978                 :           2 : parse_symenc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
     979                 :             : {
     980                 :             :     int         res;
     981                 :           2 :     PGP_CFB    *cfb = NULL;
     982                 :           2 :     PullFilter *pf_decrypt = NULL;
     983                 :           2 :     PullFilter *pf_prefix = NULL;
     984                 :             : 
     985                 :           2 :     res = pgp_cfb_create(&cfb, ctx->cipher_algo,
     986                 :           2 :                          ctx->sess_key, ctx->sess_key_len, 1, NULL);
     987         [ -  + ]:           2 :     if (res < 0)
     988                 :           0 :         goto out;
     989                 :             : 
     990                 :           2 :     res = pullf_create(&pf_decrypt, &pgp_decrypt_filter, cfb, pkt);
     991         [ -  + ]:           2 :     if (res < 0)
     992                 :           0 :         goto out;
     993                 :             : 
     994                 :           2 :     res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_decrypt);
     995         [ -  + ]:           2 :     if (res < 0)
     996                 :           0 :         goto out;
     997                 :             : 
     998                 :           2 :     res = process_data_packets(ctx, dst, pf_prefix, ALLOW_COMPR, NO_MDC);
     999                 :             : 
    1000                 :           2 : out:
    1001         [ +  - ]:           2 :     if (pf_prefix)
    1002                 :           2 :         pullf_free(pf_prefix);
    1003         [ +  - ]:           2 :     if (pf_decrypt)
    1004                 :           2 :         pullf_free(pf_decrypt);
    1005         [ +  - ]:           2 :     if (cfb)
    1006                 :           2 :         pgp_cfb_free(cfb);
    1007                 :             : 
    1008                 :           2 :     return res;
    1009                 :             : }
    1010                 :             : 
    1011                 :             : static int
    1012                 :          71 : parse_symenc_mdc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
    1013                 :             : {
    1014                 :             :     int         res;
    1015                 :          71 :     PGP_CFB    *cfb = NULL;
    1016                 :          71 :     PullFilter *pf_decrypt = NULL;
    1017                 :          71 :     PullFilter *pf_prefix = NULL;
    1018                 :          71 :     PullFilter *pf_mdc = NULL;
    1019                 :             :     uint8       ver;
    1020                 :             : 
    1021         [ -  + ]:          71 :     GETBYTE(pkt, ver);
    1022         [ -  + ]:          71 :     if (ver != 1)
    1023                 :             :     {
    1024                 :           0 :         px_debug("parse_symenc_mdc_data: pkt ver != 1");
    1025                 :           0 :         return PXE_PGP_CORRUPT_DATA;
    1026                 :             :     }
    1027                 :             : 
    1028                 :          71 :     res = pgp_cfb_create(&cfb, ctx->cipher_algo,
    1029                 :          71 :                          ctx->sess_key, ctx->sess_key_len, 0, NULL);
    1030         [ -  + ]:          71 :     if (res < 0)
    1031                 :           0 :         goto out;
    1032                 :             : 
    1033                 :          71 :     res = pullf_create(&pf_decrypt, &pgp_decrypt_filter, cfb, pkt);
    1034         [ -  + ]:          71 :     if (res < 0)
    1035                 :           0 :         goto out;
    1036                 :             : 
    1037                 :          71 :     res = pullf_create(&pf_mdc, &mdc_filter, ctx, pf_decrypt);
    1038         [ -  + ]:          71 :     if (res < 0)
    1039                 :           0 :         goto out;
    1040                 :             : 
    1041                 :          71 :     res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_mdc);
    1042         [ -  + ]:          71 :     if (res < 0)
    1043                 :           0 :         goto out;
    1044                 :             : 
    1045                 :          71 :     res = process_data_packets(ctx, dst, pf_prefix, ALLOW_COMPR, NEED_MDC);
    1046                 :             : 
    1047                 :          71 : out:
    1048         [ +  - ]:          71 :     if (pf_prefix)
    1049                 :          71 :         pullf_free(pf_prefix);
    1050         [ +  - ]:          71 :     if (pf_mdc)
    1051                 :          71 :         pullf_free(pf_mdc);
    1052         [ +  - ]:          71 :     if (pf_decrypt)
    1053                 :          71 :         pullf_free(pf_decrypt);
    1054         [ +  - ]:          71 :     if (cfb)
    1055                 :          71 :         pgp_cfb_free(cfb);
    1056                 :             : 
    1057                 :          71 :     return res;
    1058                 :             : }
    1059                 :             : 
    1060                 :             : /*
    1061                 :             :  * skip over packet contents
    1062                 :             :  */
    1063                 :             : int
    1064                 :         159 : pgp_skip_packet(PullFilter *pkt)
    1065                 :             : {
    1066                 :         159 :     int         res = 1;
    1067                 :             :     uint8      *tmp;
    1068                 :             : 
    1069         [ +  + ]:         472 :     while (res > 0)
    1070                 :         313 :         res = pullf_read(pkt, 32 * 1024, &tmp);
    1071                 :         159 :     return res;
    1072                 :             : }
    1073                 :             : 
    1074                 :             : /*
    1075                 :             :  * expect to be at packet end, any data is error
    1076                 :             :  */
    1077                 :             : int
    1078                 :          28 : pgp_expect_packet_end(PullFilter *pkt)
    1079                 :             : {
    1080                 :             :     int         res;
    1081                 :             :     uint8      *tmp;
    1082                 :             : 
    1083                 :          28 :     res = pullf_read(pkt, 32 * 1024, &tmp);
    1084         [ -  + ]:          28 :     if (res > 0)
    1085                 :             :     {
    1086                 :           0 :         px_debug("pgp_expect_packet_end: got data");
    1087                 :           0 :         return PXE_PGP_CORRUPT_DATA;
    1088                 :             :     }
    1089                 :          28 :     return res;
    1090                 :             : }
    1091                 :             : 
    1092                 :             : int
    1093                 :          75 : pgp_decrypt(PGP_Context *ctx, MBuf *msrc, MBuf *mdst)
    1094                 :             : {
    1095                 :             :     int         res;
    1096                 :          75 :     PullFilter *src = NULL;
    1097                 :          75 :     PullFilter *pkt = NULL;
    1098                 :             :     uint8       tag;
    1099                 :             :     int         len;
    1100                 :          75 :     int         got_key = 0;
    1101                 :          75 :     int         got_data = 0;
    1102                 :             : 
    1103                 :          75 :     res = pullf_create_mbuf_reader(&src, msrc);
    1104                 :             : 
    1105         [ +  + ]:         223 :     while (res >= 0)
    1106                 :             :     {
    1107                 :         216 :         res = pgp_parse_pkt_hdr(src, &tag, &len, NO_CTX_SIZE);
    1108         [ +  + ]:         216 :         if (res <= 0)
    1109                 :          68 :             break;
    1110                 :             : 
    1111                 :         148 :         res = pgp_create_pkt_reader(&pkt, src, len, res, ctx);
    1112         [ -  + ]:         148 :         if (res < 0)
    1113                 :           0 :             break;
    1114                 :             : 
    1115                 :         148 :         res = PXE_PGP_CORRUPT_DATA;
    1116   [ -  +  +  +  :         148 :         switch (tag)
                   +  - ]
    1117                 :             :         {
    1118                 :           0 :             case PGP_PKT_MARKER:
    1119                 :           0 :                 res = pgp_skip_packet(pkt);
    1120                 :           0 :                 break;
    1121                 :          15 :             case PGP_PKT_PUBENCRYPTED_SESSKEY:
    1122                 :             :                 /* fixme: skip those */
    1123                 :          15 :                 res = pgp_parse_pubenc_sesskey(ctx, pkt);
    1124                 :          15 :                 got_key = 1;
    1125                 :          15 :                 break;
    1126                 :          60 :             case PGP_PKT_SYMENCRYPTED_SESSKEY:
    1127         [ -  + ]:          60 :                 if (got_key)
    1128                 :             : 
    1129                 :             :                     /*
    1130                 :             :                      * Theoretically, there could be several keys, both public
    1131                 :             :                      * and symmetric, all of which encrypt same session key.
    1132                 :             :                      * Decrypt should try with each one, before failing.
    1133                 :             :                      */
    1134                 :           0 :                     px_debug("pgp_decrypt: using first of several keys");
    1135                 :             :                 else
    1136                 :             :                 {
    1137                 :          60 :                     got_key = 1;
    1138                 :          60 :                     res = parse_symenc_sesskey(ctx, pkt);
    1139                 :             :                 }
    1140                 :          60 :                 break;
    1141                 :           2 :             case PGP_PKT_SYMENCRYPTED_DATA:
    1142         [ -  + ]:           2 :                 if (!got_key)
    1143                 :           0 :                     px_debug("pgp_decrypt: have data but no key");
    1144         [ -  + ]:           2 :                 else if (got_data)
    1145                 :           0 :                     px_debug("pgp_decrypt: got second data packet");
    1146                 :             :                 else
    1147                 :             :                 {
    1148                 :           2 :                     got_data = 1;
    1149                 :           2 :                     ctx->disable_mdc = 1;
    1150                 :           2 :                     res = parse_symenc_data(ctx, pkt, mdst);
    1151                 :             :                 }
    1152                 :           2 :                 break;
    1153                 :          71 :             case PGP_PKT_SYMENCRYPTED_DATA_MDC:
    1154         [ -  + ]:          71 :                 if (!got_key)
    1155                 :           0 :                     px_debug("pgp_decrypt: have data but no key");
    1156         [ -  + ]:          71 :                 else if (got_data)
    1157                 :           0 :                     px_debug("pgp_decrypt: several data pkts not supported");
    1158                 :             :                 else
    1159                 :             :                 {
    1160                 :          71 :                     got_data = 1;
    1161                 :          71 :                     ctx->disable_mdc = 0;
    1162                 :          71 :                     res = parse_symenc_mdc_data(ctx, pkt, mdst);
    1163                 :             :                 }
    1164                 :          71 :                 break;
    1165                 :           0 :             default:
    1166                 :           0 :                 px_debug("pgp_decrypt: unknown tag: 0x%02x", tag);
    1167                 :             :         }
    1168                 :         148 :         pullf_free(pkt);
    1169                 :         148 :         pkt = NULL;
    1170                 :             :     }
    1171                 :             : 
    1172         [ -  + ]:          75 :     if (pkt)
    1173                 :           0 :         pullf_free(pkt);
    1174                 :             : 
    1175         [ +  - ]:          75 :     if (src)
    1176                 :          75 :         pullf_free(src);
    1177                 :             : 
    1178         [ +  + ]:          75 :     if (res < 0)
    1179                 :           7 :         return res;
    1180                 :             : 
    1181                 :             :     /*
    1182                 :             :      * Report a failure of the prefix_init() "quick check" now, rather than
    1183                 :             :      * upon detection, to hinder timing attacks.  pgcrypto is not generally
    1184                 :             :      * secure against timing attacks, but this helps.
    1185                 :             :      */
    1186   [ +  -  -  + ]:          68 :     if (!got_data || ctx->corrupt_prefix)
    1187                 :           0 :         return PXE_PGP_CORRUPT_DATA;
    1188                 :             : 
    1189                 :             :     /*
    1190                 :             :      * Code interpreting purportedly-decrypted data prior to this stage shall
    1191                 :             :      * report no error other than PXE_PGP_CORRUPT_DATA.  (PXE_BUG is okay so
    1192                 :             :      * long as it remains unreachable.)  This ensures that an attacker able to
    1193                 :             :      * choose a ciphertext and receive a corresponding decryption error
    1194                 :             :      * message cannot use that oracle to gather clues about the decryption
    1195                 :             :      * key.  See "An Attack on CFB Mode Encryption As Used By OpenPGP" by
    1196                 :             :      * Serge Mister and Robert Zuccherato.
    1197                 :             :      *
    1198                 :             :      * A problematic value in the first octet of a Literal Data or Compressed
    1199                 :             :      * Data packet may indicate a simple user error, such as the need to call
    1200                 :             :      * pgp_sym_decrypt_bytea instead of pgp_sym_decrypt.  Occasionally,
    1201                 :             :      * though, it is the first symptom of the encryption key not matching the
    1202                 :             :      * decryption key.  When this was the only problem encountered, report a
    1203                 :             :      * specific error to guide the user; otherwise, we will have reported
    1204                 :             :      * PXE_PGP_CORRUPT_DATA before now.  A key mismatch makes the other errors
    1205                 :             :      * into red herrings, and this avoids leaking clues to attackers.
    1206                 :             :      */
    1207         [ +  + ]:          68 :     if (ctx->unsupported_compr)
    1208                 :           1 :         return PXE_PGP_UNSUPPORTED_COMPR;
    1209         [ +  + ]:          67 :     if (ctx->unexpected_binary)
    1210                 :           3 :         return PXE_PGP_NOT_TEXT;
    1211                 :             : 
    1212                 :          64 :     return res;
    1213                 :             : }
        

Generated by: LCOV version 2.0-1