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

Generated by: LCOV version 1.14