LCOV - code coverage report
Current view: top level - contrib/pgcrypto - pgp-decrypt.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 80.1 % 558 447
Test Date: 2026-03-02 07:14:52 Functions: 100.0 % 31 31
Legend: Lines:     hit not hit

            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