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: 2024-03-29 13:11:54 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             :     /* Make sure we have space for prefix */
     254         144 :     if (len > PGP_MAX_BLOCK)
     255           0 :         return PXE_BUG;
     256             : 
     257         144 :     res = pullf_read_max(src, len + 2, &buf, tmpbuf);
     258         144 :     if (res < 0)
     259           0 :         return res;
     260         144 :     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         144 :     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         144 :     px_memset(tmpbuf, 0, sizeof(tmpbuf));
     274         144 :     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         152 : decrypt_init(void **priv_p, void *arg, PullFilter *src)
     288             : {
     289         152 :     PGP_CFB    *cfb = arg;
     290             : 
     291         152 :     *priv_p = cfb;
     292             : 
     293             :     /* we need to write somewhere, so ask for a buffer */
     294         152 :     return 4096;
     295             : }
     296             : 
     297             : static int
     298        1646 : decrypt_read(void *priv, PullFilter *src, int len,
     299             :              uint8 **data_p, uint8 *buf, int buflen)
     300             : {
     301        1646 :     PGP_CFB    *cfb = priv;
     302             :     uint8      *tmp;
     303             :     int         res;
     304             : 
     305        1646 :     res = pullf_read(src, len, &tmp);
     306        1646 :     if (res > 0)
     307             :     {
     308        1494 :         pgp_cfb_decrypt(cfb, tmp, res, buf);
     309        1494 :         *data_p = buf;
     310             :     }
     311        1646 :     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         140 : mdc_init(void **priv_p, void *arg, PullFilter *src)
     325             : {
     326         140 :     PGP_Context *ctx = arg;
     327             : 
     328         140 :     *priv_p = ctx;
     329         140 :     return pgp_load_digest(PGP_DIGEST_SHA1, &ctx->mdc_ctx);
     330             : }
     331             : 
     332             : static void
     333         140 : mdc_free(void *priv)
     334             : {
     335         140 :     PGP_Context *ctx = priv;
     336             : 
     337         140 :     if (ctx->use_mdcbuf_filter)
     338           6 :         return;
     339         134 :     px_md_free(ctx->mdc_ctx);
     340         134 :     ctx->mdc_ctx = NULL;
     341             : }
     342             : 
     343             : static int
     344         132 : 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         132 :     if (ctx->use_mdcbuf_filter)
     353           0 :         return PXE_BUG;
     354             : 
     355             :     /* It's SHA1 */
     356         132 :     if (len != 20)
     357           0 :         return PXE_PGP_CORRUPT_DATA;
     358             : 
     359             :     /* mdc_read should not call px_md_update */
     360         132 :     ctx->in_mdc_pkt = 1;
     361             : 
     362             :     /* read data */
     363         132 :     res = pullf_read_max(src, len, &data, tmpbuf);
     364         132 :     if (res < 0)
     365           0 :         return res;
     366         132 :     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         132 :     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         132 :     px_md_finish(ctx->mdc_ctx, hash);
     383         132 :     res = memcmp(hash, data, 20);
     384         132 :     px_memset(hash, 0, 20);
     385         132 :     px_memset(tmpbuf, 0, sizeof(tmpbuf));
     386         132 :     if (res != 0)
     387             :     {
     388           0 :         px_debug("mdc_finish: mdc failed");
     389           0 :         return PXE_PGP_CORRUPT_DATA;
     390             :     }
     391         132 :     ctx->mdc_checked = 1;
     392         132 :     return 0;
     393             : }
     394             : 
     395             : static int
     396        1568 : mdc_read(void *priv, PullFilter *src, int len,
     397             :          uint8 **data_p, uint8 *buf, int buflen)
     398             : {
     399             :     int         res;
     400        1568 :     PGP_Context *ctx = priv;
     401             : 
     402             :     /* skip this filter? */
     403        1568 :     if (ctx->use_mdcbuf_filter || ctx->in_mdc_pkt)
     404         278 :         return pullf_read(src, len, data_p);
     405             : 
     406        1290 :     res = pullf_read(src, len, data_p);
     407        1290 :     if (res < 0)
     408           0 :         return res;
     409        1290 :     if (res == 0)
     410             :     {
     411           0 :         px_debug("mdc_read: unexpected eof");
     412           0 :         return PXE_PGP_CORRUPT_DATA;
     413             :     }
     414        1290 :     px_md_update(ctx->mdc_ctx, *data_p, res);
     415             : 
     416        1290 :     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           6 : mdcbuf_init(void **priv_p, void *arg, PullFilter *src)
     447             : {
     448           6 :     PGP_Context *ctx = arg;
     449             :     struct MDCBufData *st;
     450             : 
     451           6 :     st = palloc0(sizeof(*st));
     452           6 :     st->buflen = sizeof(st->buf);
     453           6 :     st->ctx = ctx;
     454           6 :     *priv_p = st;
     455             : 
     456             :     /* take over the work of mdc_filter */
     457           6 :     ctx->use_mdcbuf_filter = 1;
     458             : 
     459           6 :     return 0;
     460             : }
     461             : 
     462             : static int
     463           6 : mdcbuf_finish(struct MDCBufData *st)
     464             : {
     465             :     uint8       hash[20];
     466             :     int         res;
     467             : 
     468           6 :     st->eof = 1;
     469             : 
     470           6 :     if (st->mdc_buf[0] != 0xD3 || st->mdc_buf[1] != 0x14)
     471             :     {
     472           4 :         px_debug("mdcbuf_finish: bad MDC pkt hdr");
     473           4 :         return PXE_PGP_CORRUPT_DATA;
     474             :     }
     475           2 :     px_md_update(st->ctx->mdc_ctx, st->mdc_buf, 2);
     476           2 :     px_md_finish(st->ctx->mdc_ctx, hash);
     477           2 :     res = memcmp(hash, st->mdc_buf + 2, 20);
     478           2 :     px_memset(hash, 0, 20);
     479           2 :     if (res)
     480             :     {
     481           0 :         px_debug("mdcbuf_finish: MDC does not match");
     482           0 :         res = PXE_PGP_CORRUPT_DATA;
     483             :     }
     484           2 :     return res;
     485             : }
     486             : 
     487             : static void
     488          12 : mdcbuf_load_data(struct MDCBufData *st, uint8 *src, int len)
     489             : {
     490          12 :     uint8      *dst = st->pos + st->avail;
     491             : 
     492          12 :     memcpy(dst, src, len);
     493          12 :     px_md_update(st->ctx->mdc_ctx, src, len);
     494          12 :     st->avail += len;
     495          12 : }
     496             : 
     497             : static void
     498           6 : mdcbuf_load_mdc(struct MDCBufData *st, uint8 *src, int len)
     499             : {
     500           6 :     memmove(st->mdc_buf + st->mdc_avail, src, len);
     501           6 :     st->mdc_avail += len;
     502           6 : }
     503             : 
     504             : static int
     505          12 : 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          12 :     if (st->avail > 0 && st->pos != st->buf)
     513           6 :         memmove(st->buf, st->pos, st->avail);
     514          12 :     st->pos = st->buf;
     515             : 
     516             :     /* read new data */
     517          12 :     need = st->buflen + 22 - st->avail - st->mdc_avail;
     518          12 :     res = pullf_read(src, need, &data);
     519          12 :     if (res < 0)
     520           0 :         return res;
     521          12 :     if (res == 0)
     522           6 :         return mdcbuf_finish(st);
     523             : 
     524             :     /* add to buffer */
     525           6 :     if (res >= 22)
     526             :     {
     527           6 :         mdcbuf_load_data(st, st->mdc_buf, st->mdc_avail);
     528           6 :         st->mdc_avail = 0;
     529             : 
     530           6 :         mdcbuf_load_data(st, data, res - 22);
     531           6 :         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           6 :     return 0;
     546             : }
     547             : 
     548             : static int
     549          20 : mdcbuf_read(void *priv, PullFilter *src, int len,
     550             :             uint8 **data_p, uint8 *buf, int buflen)
     551             : {
     552          20 :     struct MDCBufData *st = priv;
     553             :     int         res;
     554             : 
     555          20 :     if (!st->eof && len > st->avail)
     556             :     {
     557          12 :         res = mdcbuf_refill(st, src);
     558          12 :         if (res < 0)
     559           4 :             return res;
     560             :     }
     561             : 
     562          16 :     if (len > st->avail)
     563           4 :         len = st->avail;
     564             : 
     565          16 :     *data_p = st->pos;
     566          16 :     st->pos += len;
     567          16 :     st->avail -= len;
     568          16 :     return len;
     569             : }
     570             : 
     571             : static void
     572           6 : mdcbuf_free(void *priv)
     573             : {
     574           6 :     struct MDCBufData *st = priv;
     575             : 
     576           6 :     px_md_free(st->ctx->mdc_ctx);
     577           6 :     st->ctx->mdc_ctx = NULL;
     578           6 :     px_memset(st, 0, sizeof(*st));
     579           6 :     pfree(st);
     580           6 : }
     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           8 : decrypt_key(PGP_Context *ctx, const uint8 *src, int len)
     592             : {
     593             :     int         res;
     594             :     uint8       algo;
     595             :     PGP_CFB    *cfb;
     596             : 
     597           8 :     res = pgp_cfb_create(&cfb, ctx->s2k_cipher_algo,
     598           8 :                          ctx->s2k.key, ctx->s2k.key_len, 0, NULL);
     599           8 :     if (res < 0)
     600           0 :         return res;
     601             : 
     602           8 :     pgp_cfb_decrypt(cfb, src, 1, &algo);
     603           8 :     src++;
     604           8 :     len--;
     605             : 
     606           8 :     pgp_cfb_decrypt(cfb, src, len, ctx->sess_key);
     607           8 :     pgp_cfb_free(cfb);
     608           8 :     ctx->sess_key_len = len;
     609           8 :     ctx->cipher_algo = algo;
     610             : 
     611           8 :     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           8 :     return 0;
     618             : }
     619             : 
     620             : /*
     621             :  * Handle key packet
     622             :  */
     623             : static int
     624         118 : 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         118 :     GETBYTE(src, ver);
     632         118 :     GETBYTE(src, ctx->s2k_cipher_algo);
     633         118 :     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         118 :     res = pgp_s2k_read(src, &ctx->s2k);
     643         118 :     if (res < 0)
     644           0 :         return res;
     645         118 :     ctx->s2k_mode = ctx->s2k.mode;
     646         118 :     ctx->s2k_count = s2k_decode_count(ctx->s2k.iter);
     647         118 :     ctx->s2k_digest_algo = ctx->s2k.digest_algo;
     648             : 
     649             :     /*
     650             :      * generate key from password
     651             :      */
     652         118 :     res = pgp_s2k_process(&ctx->s2k, ctx->s2k_cipher_algo,
     653             :                           ctx->sym_key, ctx->sym_key_len);
     654         118 :     if (res < 0)
     655           0 :         return res;
     656             : 
     657             :     /*
     658             :      * do we have separate session key?
     659             :      */
     660         118 :     res = pullf_read_max(src, PGP_MAX_KEY + 2, &p, tmpbuf);
     661         118 :     if (res < 0)
     662           0 :         return res;
     663             : 
     664         118 :     if (res == 0)
     665             :     {
     666             :         /*
     667             :          * no, s2k key is session key
     668             :          */
     669         110 :         memcpy(ctx->sess_key, ctx->s2k.key, ctx->s2k.key_len);
     670         110 :         ctx->sess_key_len = ctx->s2k.key_len;
     671         110 :         ctx->cipher_algo = ctx->s2k_cipher_algo;
     672         110 :         res = 0;
     673         110 :         ctx->use_sess_key = 0;
     674             :     }
     675             :     else
     676             :     {
     677             :         /*
     678             :          * yes, decrypt it
     679             :          */
     680           8 :         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           8 :         ctx->use_sess_key = 1;
     686           8 :         res = decrypt_key(ctx, p, res);
     687             :     }
     688             : 
     689         118 :     px_memset(tmpbuf, 0, sizeof(tmpbuf));
     690         118 :     return res;
     691             : }
     692             : 
     693             : static int
     694           4 : copy_crlf(MBuf *dst, uint8 *data, int len, int *got_cr)
     695             : {
     696           4 :     uint8      *data_end = data + len;
     697             :     uint8       tmpbuf[1024];
     698           4 :     uint8      *tmp_end = tmpbuf + sizeof(tmpbuf);
     699             :     uint8      *p;
     700             :     int         res;
     701             : 
     702           4 :     p = tmpbuf;
     703           4 :     if (*got_cr)
     704             :     {
     705           0 :         if (*data != '\n')
     706           0 :             *p++ = '\r';
     707           0 :         *got_cr = 0;
     708             :     }
     709          94 :     while (data < data_end)
     710             :     {
     711          94 :         if (*data == '\r')
     712             :         {
     713          28 :             if (data + 1 < data_end)
     714             :             {
     715          24 :                 if (*(data + 1) == '\n')
     716          14 :                     data++;
     717             :             }
     718             :             else
     719             :             {
     720           4 :                 *got_cr = 1;
     721           4 :                 break;
     722             :             }
     723             :         }
     724          90 :         *p++ = *data++;
     725          90 :         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           4 :     if (p - tmpbuf > 0)
     734             :     {
     735           4 :         res = mbuf_append(dst, tmpbuf, p - tmpbuf);
     736           4 :         if (res < 0)
     737           0 :             return res;
     738             :     }
     739           4 :     px_memset(tmpbuf, 0, sizeof(tmpbuf));
     740           4 :     return 0;
     741             : }
     742             : 
     743             : static int
     744         138 : 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         138 :     int         got_cr = 0;
     752             : 
     753         138 :     GETBYTE(pkt, type);
     754         138 :     GETBYTE(pkt, name_len);
     755             : 
     756             :     /* skip name */
     757         186 :     while (name_len > 0)
     758             :     {
     759          48 :         res = pullf_read(pkt, name_len, &buf);
     760          48 :         if (res < 0)
     761           0 :             return res;
     762          48 :         if (res == 0)
     763           0 :             break;
     764          48 :         name_len -= res;
     765             :     }
     766         138 :     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         138 :     res = pullf_read_max(pkt, 4, &buf, tmpbuf);
     774         138 :     if (res != 4)
     775             :     {
     776           0 :         px_debug("parse_literal_data: unexpected eof");
     777           0 :         return PXE_PGP_CORRUPT_DATA;
     778             :     }
     779         138 :     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         138 :     if (ctx->text_mode)
     786         130 :         if (type != 't' && type != 'u')
     787             :         {
     788           8 :             px_debug("parse_literal_data: data type=%c", type);
     789           8 :             ctx->unexpected_binary = true;
     790             :         }
     791             : 
     792         138 :     ctx->unicode_mode = (type == 'u') ? 1 : 0;
     793             : 
     794             :     /* read data */
     795             :     while (1)
     796             :     {
     797         318 :         res = pullf_read(pkt, 32 * 1024, &buf);
     798         318 :         if (res <= 0)
     799         138 :             break;
     800             : 
     801         180 :         if (ctx->text_mode && ctx->convert_crlf)
     802           4 :             res = copy_crlf(dst, buf, res, &got_cr);
     803             :         else
     804         176 :             res = mbuf_append(dst, buf, res);
     805         180 :         if (res < 0)
     806           0 :             break;
     807             :     }
     808         138 :     if (res >= 0 && got_cr)
     809           4 :         res = mbuf_append(dst, (const uint8 *) "\r", 1);
     810         138 :     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          12 : 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          12 :     GETBYTE(pkt, type);
     826             : 
     827          12 :     ctx->compress_algo = type;
     828          12 :     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           8 :         case PGP_COMPR_ZIP:
     835             :         case PGP_COMPR_ZLIB:
     836           8 :             res = pgp_decompress_filter(&pf_decompr, ctx, pkt);
     837           8 :             if (res >= 0)
     838             :             {
     839           8 :                 res = process_data_packets(ctx, dst, pf_decompr,
     840             :                                            NO_COMPR, NO_MDC);
     841           8 :                 pullf_free(pf_decompr);
     842             :             }
     843           8 :             break;
     844             : 
     845           4 :         case PGP_COMPR_BZIP2:
     846           4 :             px_debug("parse_compressed_data: bzip2 unsupported");
     847             :             /* report error in pgp_decrypt() */
     848           4 :             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           6 :                 res = pullf_read(pkt, 32 * 1024, &discard_buf);
     857           6 :                 if (res <= 0)
     858           4 :                     break;
     859             :             }
     860             : 
     861           4 :             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          12 :     return res;
     869             : }
     870             : 
     871             : static int
     872         152 : 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         152 :     int         got_data = 0;
     879         152 :     int         got_mdc = 0;
     880         152 :     PullFilter *pkt = NULL;
     881             : 
     882             :     while (1)
     883             :     {
     884         430 :         res = pgp_parse_pkt_hdr(src, &tag, &len, ALLOW_CTX_SIZE);
     885         430 :         if (res <= 0)
     886         146 :             break;
     887             : 
     888             : 
     889             :         /* mdc packet should be last */
     890         284 :         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         284 :         if (need_mdc && res == PKT_CONTEXT)
     902           6 :             res = pullf_create(&pkt, &mdcbuf_filter, ctx, src);
     903             :         else
     904         278 :             res = pgp_create_pkt_reader(&pkt, src, len, res, ctx);
     905         284 :         if (res < 0)
     906           0 :             break;
     907             : 
     908         284 :         switch (tag)
     909             :         {
     910         138 :             case PGP_PKT_LITERAL_DATA:
     911         138 :                 got_data = 1;
     912         138 :                 res = parse_literal_data(ctx, dst, pkt);
     913         138 :                 break;
     914          12 :             case PGP_PKT_COMPRESSED_DATA:
     915          12 :                 if (allow_compr == 0)
     916             :                 {
     917           0 :                     px_debug("process_data_packets: unexpected compression");
     918           0 :                     res = PXE_PGP_CORRUPT_DATA;
     919             :                 }
     920          12 :                 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          12 :                     got_data = 1;
     931          12 :                     res = parse_compressed_data(ctx, dst, pkt);
     932             :                 }
     933          12 :                 break;
     934         132 :             case PGP_PKT_MDC:
     935         132 :                 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         132 :                 res = mdc_finish(ctx, pkt, len);
     943         132 :                 if (res >= 0)
     944         132 :                     got_mdc = 1;
     945         132 :                 break;
     946           2 :             default:
     947           2 :                 px_debug("process_data_packets: unexpected pkt tag=%d", tag);
     948           2 :                 res = PXE_PGP_CORRUPT_DATA;
     949             :         }
     950             : 
     951         284 :         pullf_free(pkt);
     952         284 :         pkt = NULL;
     953             : 
     954         284 :         if (res < 0)
     955           6 :             break;
     956             :     }
     957             : 
     958         152 :     if (pkt)
     959           0 :         pullf_free(pkt);
     960             : 
     961         152 :     if (res < 0)
     962           6 :         return res;
     963             : 
     964         146 :     if (!got_data)
     965             :     {
     966           0 :         px_debug("process_data_packets: no data");
     967           0 :         res = PXE_PGP_CORRUPT_DATA;
     968             :     }
     969         146 :     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         146 :     return res;
     975             : }
     976             : 
     977             : static int
     978           4 : parse_symenc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
     979             : {
     980             :     int         res;
     981           4 :     PGP_CFB    *cfb = NULL;
     982           4 :     PullFilter *pf_decrypt = NULL;
     983           4 :     PullFilter *pf_prefix = NULL;
     984             : 
     985           4 :     res = pgp_cfb_create(&cfb, ctx->cipher_algo,
     986           4 :                          ctx->sess_key, ctx->sess_key_len, 1, NULL);
     987           4 :     if (res < 0)
     988           0 :         goto out;
     989             : 
     990           4 :     res = pullf_create(&pf_decrypt, &pgp_decrypt_filter, cfb, pkt);
     991           4 :     if (res < 0)
     992           0 :         goto out;
     993             : 
     994           4 :     res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_decrypt);
     995           4 :     if (res < 0)
     996           0 :         goto out;
     997             : 
     998           4 :     res = process_data_packets(ctx, dst, pf_prefix, ALLOW_COMPR, NO_MDC);
     999             : 
    1000           4 : out:
    1001           4 :     if (pf_prefix)
    1002           4 :         pullf_free(pf_prefix);
    1003           4 :     if (pf_decrypt)
    1004           4 :         pullf_free(pf_decrypt);
    1005           4 :     if (cfb)
    1006           4 :         pgp_cfb_free(cfb);
    1007             : 
    1008           4 :     return res;
    1009             : }
    1010             : 
    1011             : static int
    1012         140 : parse_symenc_mdc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
    1013             : {
    1014             :     int         res;
    1015         140 :     PGP_CFB    *cfb = NULL;
    1016         140 :     PullFilter *pf_decrypt = NULL;
    1017         140 :     PullFilter *pf_prefix = NULL;
    1018         140 :     PullFilter *pf_mdc = NULL;
    1019             :     uint8       ver;
    1020             : 
    1021         140 :     GETBYTE(pkt, ver);
    1022         140 :     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         140 :     res = pgp_cfb_create(&cfb, ctx->cipher_algo,
    1029         140 :                          ctx->sess_key, ctx->sess_key_len, 0, NULL);
    1030         140 :     if (res < 0)
    1031           0 :         goto out;
    1032             : 
    1033         140 :     res = pullf_create(&pf_decrypt, &pgp_decrypt_filter, cfb, pkt);
    1034         140 :     if (res < 0)
    1035           0 :         goto out;
    1036             : 
    1037         140 :     res = pullf_create(&pf_mdc, &mdc_filter, ctx, pf_decrypt);
    1038         140 :     if (res < 0)
    1039           0 :         goto out;
    1040             : 
    1041         140 :     res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_mdc);
    1042         140 :     if (res < 0)
    1043           0 :         goto out;
    1044             : 
    1045         140 :     res = process_data_packets(ctx, dst, pf_prefix, ALLOW_COMPR, NEED_MDC);
    1046             : 
    1047         140 : out:
    1048         140 :     if (pf_prefix)
    1049         140 :         pullf_free(pf_prefix);
    1050         140 :     if (pf_mdc)
    1051         140 :         pullf_free(pf_mdc);
    1052         140 :     if (pf_decrypt)
    1053         140 :         pullf_free(pf_decrypt);
    1054         140 :     if (cfb)
    1055         140 :         pgp_cfb_free(cfb);
    1056             : 
    1057         140 :     return res;
    1058             : }
    1059             : 
    1060             : /*
    1061             :  * skip over packet contents
    1062             :  */
    1063             : int
    1064         318 : pgp_skip_packet(PullFilter *pkt)
    1065             : {
    1066         318 :     int         res = 1;
    1067             :     uint8      *tmp;
    1068             : 
    1069         944 :     while (res > 0)
    1070         626 :         res = pullf_read(pkt, 32 * 1024, &tmp);
    1071         318 :     return res;
    1072             : }
    1073             : 
    1074             : /*
    1075             :  * expect to be at packet end, any data is error
    1076             :  */
    1077             : int
    1078          54 : pgp_expect_packet_end(PullFilter *pkt)
    1079             : {
    1080             :     int         res;
    1081             :     uint8      *tmp;
    1082             : 
    1083          54 :     res = pullf_read(pkt, 32 * 1024, &tmp);
    1084          54 :     if (res > 0)
    1085             :     {
    1086           0 :         px_debug("pgp_expect_packet_end: got data");
    1087           0 :         return PXE_PGP_CORRUPT_DATA;
    1088             :     }
    1089          54 :     return res;
    1090             : }
    1091             : 
    1092             : int
    1093         146 : pgp_decrypt(PGP_Context *ctx, MBuf *msrc, MBuf *mdst)
    1094             : {
    1095             :     int         res;
    1096         146 :     PullFilter *src = NULL;
    1097         146 :     PullFilter *pkt = NULL;
    1098             :     uint8       tag;
    1099             :     int         len;
    1100         146 :     int         got_key = 0;
    1101         146 :     int         got_data = 0;
    1102             : 
    1103         146 :     res = pullf_create_mbuf_reader(&src, msrc);
    1104             : 
    1105         436 :     while (res >= 0)
    1106             :     {
    1107         428 :         res = pgp_parse_pkt_hdr(src, &tag, &len, NO_CTX_SIZE);
    1108         428 :         if (res <= 0)
    1109         138 :             break;
    1110             : 
    1111         290 :         res = pgp_create_pkt_reader(&pkt, src, len, res, ctx);
    1112         290 :         if (res < 0)
    1113           0 :             break;
    1114             : 
    1115         290 :         res = PXE_PGP_CORRUPT_DATA;
    1116         290 :         switch (tag)
    1117             :         {
    1118           0 :             case PGP_PKT_MARKER:
    1119           0 :                 res = pgp_skip_packet(pkt);
    1120           0 :                 break;
    1121          28 :             case PGP_PKT_PUBENCRYPTED_SESSKEY:
    1122             :                 /* fixme: skip those */
    1123          28 :                 res = pgp_parse_pubenc_sesskey(ctx, pkt);
    1124          28 :                 got_key = 1;
    1125          28 :                 break;
    1126         118 :             case PGP_PKT_SYMENCRYPTED_SESSKEY:
    1127         118 :                 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         118 :                     got_key = 1;
    1138         118 :                     res = parse_symenc_sesskey(ctx, pkt);
    1139             :                 }
    1140         118 :                 break;
    1141           4 :             case PGP_PKT_SYMENCRYPTED_DATA:
    1142           4 :                 if (!got_key)
    1143           0 :                     px_debug("pgp_decrypt: have data but no key");
    1144           4 :                 else if (got_data)
    1145           0 :                     px_debug("pgp_decrypt: got second data packet");
    1146             :                 else
    1147             :                 {
    1148           4 :                     got_data = 1;
    1149           4 :                     ctx->disable_mdc = 1;
    1150           4 :                     res = parse_symenc_data(ctx, pkt, mdst);
    1151             :                 }
    1152           4 :                 break;
    1153         140 :             case PGP_PKT_SYMENCRYPTED_DATA_MDC:
    1154         140 :                 if (!got_key)
    1155           0 :                     px_debug("pgp_decrypt: have data but no key");
    1156         140 :                 else if (got_data)
    1157           0 :                     px_debug("pgp_decrypt: several data pkts not supported");
    1158             :                 else
    1159             :                 {
    1160         140 :                     got_data = 1;
    1161         140 :                     ctx->disable_mdc = 0;
    1162         140 :                     res = parse_symenc_mdc_data(ctx, pkt, mdst);
    1163             :                 }
    1164         140 :                 break;
    1165           0 :             default:
    1166           0 :                 px_debug("pgp_decrypt: unknown tag: 0x%02x", tag);
    1167             :         }
    1168         290 :         pullf_free(pkt);
    1169         290 :         pkt = NULL;
    1170             :     }
    1171             : 
    1172         146 :     if (pkt)
    1173           0 :         pullf_free(pkt);
    1174             : 
    1175         146 :     if (src)
    1176         146 :         pullf_free(src);
    1177             : 
    1178         146 :     if (res < 0)
    1179           8 :         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         138 :     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         138 :     if (ctx->unsupported_compr)
    1208           2 :         return PXE_PGP_UNSUPPORTED_COMPR;
    1209         136 :     if (ctx->unexpected_binary)
    1210           6 :         return PXE_PGP_NOT_TEXT;
    1211             : 
    1212         130 :     return res;
    1213             : }

Generated by: LCOV version 1.14