Header And Logo

PostgreSQL
| The world's most advanced open source database.

pgp-decrypt.c

Go to the documentation of this file.
00001 /*
00002  * pgp-decrypt.c
00003  *    OpenPGP decrypt.
00004  *
00005  * Copyright (c) 2005 Marko Kreen
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  *
00029  * contrib/pgcrypto/pgp-decrypt.c
00030  */
00031 
00032 #include "postgres.h"
00033 
00034 #include "px.h"
00035 #include "mbuf.h"
00036 #include "pgp.h"
00037 
00038 #define NO_CTX_SIZE     0
00039 #define ALLOW_CTX_SIZE  1
00040 #define NO_COMPR        0
00041 #define ALLOW_COMPR     1
00042 #define NO_MDC          0
00043 #define NEED_MDC        1
00044 
00045 #define PKT_NORMAL 1
00046 #define PKT_STREAM 2
00047 #define PKT_CONTEXT 3
00048 
00049 #define MAX_CHUNK (16*1024*1024)
00050 
00051 static int
00052 parse_new_len(PullFilter *src, int *len_p)
00053 {
00054     uint8       b;
00055     int         len;
00056     int         pkttype = PKT_NORMAL;
00057 
00058     GETBYTE(src, b);
00059     if (b <= 191)
00060         len = b;
00061     else if (b >= 192 && b <= 223)
00062     {
00063         len = ((unsigned) (b) - 192) << 8;
00064         GETBYTE(src, b);
00065         len += 192 + b;
00066     }
00067     else if (b == 255)
00068     {
00069         GETBYTE(src, b);
00070         len = b;
00071         GETBYTE(src, b);
00072         len = (len << 8) | b;
00073         GETBYTE(src, b);
00074         len = (len << 8) | b;
00075         GETBYTE(src, b);
00076         len = (len << 8) | b;
00077     }
00078     else
00079     {
00080         len = 1 << (b & 0x1F);
00081         pkttype = PKT_STREAM;
00082     }
00083 
00084     if (len < 0 || len > MAX_CHUNK)
00085     {
00086         px_debug("parse_new_len: weird length");
00087         return PXE_PGP_CORRUPT_DATA;
00088     }
00089 
00090     *len_p = len;
00091     return pkttype;
00092 }
00093 
00094 static int
00095 parse_old_len(PullFilter *src, int *len_p, int lentype)
00096 {
00097     uint8       b;
00098     int         len;
00099 
00100     GETBYTE(src, b);
00101     len = b;
00102 
00103     if (lentype == 1)
00104     {
00105         GETBYTE(src, b);
00106         len = (len << 8) | b;
00107     }
00108     else if (lentype == 2)
00109     {
00110         GETBYTE(src, b);
00111         len = (len << 8) | b;
00112         GETBYTE(src, b);
00113         len = (len << 8) | b;
00114         GETBYTE(src, b);
00115         len = (len << 8) | b;
00116     }
00117 
00118     if (len < 0 || len > MAX_CHUNK)
00119     {
00120         px_debug("parse_old_len: weird length");
00121         return PXE_PGP_CORRUPT_DATA;
00122     }
00123     *len_p = len;
00124     return PKT_NORMAL;
00125 }
00126 
00127 /* returns pkttype or 0 on eof */
00128 int
00129 pgp_parse_pkt_hdr(PullFilter *src, uint8 *tag, int *len_p, int allow_ctx)
00130 {
00131     int         lentype;
00132     int         res;
00133     uint8      *p;
00134 
00135     /* EOF is normal here, thus we dont use GETBYTE */
00136     res = pullf_read(src, 1, &p);
00137     if (res < 0)
00138         return res;
00139     if (res == 0)
00140         return 0;
00141 
00142     if ((*p & 0x80) == 0)
00143     {
00144         px_debug("pgp_parse_pkt_hdr: not pkt hdr");
00145         return PXE_PGP_CORRUPT_DATA;
00146     }
00147 
00148     if (*p & 0x40)
00149     {
00150         *tag = *p & 0x3f;
00151         res = parse_new_len(src, len_p);
00152     }
00153     else
00154     {
00155         lentype = *p & 3;
00156         *tag = (*p >> 2) & 0x0F;
00157         if (lentype == 3)
00158             res = allow_ctx ? PKT_CONTEXT : PXE_PGP_CORRUPT_DATA;
00159         else
00160             res = parse_old_len(src, len_p, lentype);
00161     }
00162     return res;
00163 }
00164 
00165 /*
00166  * Packet reader
00167  */
00168 struct PktData
00169 {
00170     int         type;
00171     int         len;
00172 };
00173 
00174 static int
00175 pktreader_pull(void *priv, PullFilter *src, int len,
00176                uint8 **data_p, uint8 *buf, int buflen)
00177 {
00178     int         res;
00179     struct PktData *pkt = priv;
00180 
00181     /* PKT_CONTEXT means: whatever there is */
00182     if (pkt->type == PKT_CONTEXT)
00183         return pullf_read(src, len, data_p);
00184 
00185     if (pkt->len == 0)
00186     {
00187         /* this was last chunk in stream */
00188         if (pkt->type == PKT_NORMAL)
00189             return 0;
00190 
00191         /* next chunk in stream */
00192         res = parse_new_len(src, &pkt->len);
00193         if (res < 0)
00194             return res;
00195         pkt->type = res;
00196     }
00197 
00198     if (len > pkt->len)
00199         len = pkt->len;
00200 
00201     res = pullf_read(src, len, data_p);
00202     if (res > 0)
00203         pkt->len -= res;
00204 
00205     return res;
00206 }
00207 
00208 static void
00209 pktreader_free(void *priv)
00210 {
00211     struct PktData *pkt = priv;
00212 
00213     memset(pkt, 0, sizeof(*pkt));
00214     px_free(pkt);
00215 }
00216 
00217 static struct PullFilterOps pktreader_filter = {
00218     NULL, pktreader_pull, pktreader_free
00219 };
00220 
00221 /* needs helper function to pass several parameters */
00222 int
00223 pgp_create_pkt_reader(PullFilter **pf_p, PullFilter *src, int len,
00224                       int pkttype, PGP_Context *ctx)
00225 {
00226     int         res;
00227     struct PktData *pkt = px_alloc(sizeof(*pkt));
00228 
00229     pkt->type = pkttype;
00230     pkt->len = len;
00231     res = pullf_create(pf_p, &pktreader_filter, pkt, src);
00232     if (res < 0)
00233         px_free(pkt);
00234     return res;
00235 }
00236 
00237 /*
00238  * Prefix check filter
00239  */
00240 
00241 static int
00242 prefix_init(void **priv_p, void *arg, PullFilter *src)
00243 {
00244     PGP_Context *ctx = arg;
00245     int         len;
00246     int         res;
00247     uint8      *buf;
00248     uint8       tmpbuf[PGP_MAX_BLOCK + 2];
00249 
00250     len = pgp_get_cipher_block_size(ctx->cipher_algo);
00251     if (len > sizeof(tmpbuf))
00252         return PXE_BUG;
00253 
00254     res = pullf_read_max(src, len + 2, &buf, tmpbuf);
00255     if (res < 0)
00256         return res;
00257     if (res != len + 2)
00258     {
00259         px_debug("prefix_init: short read");
00260         memset(tmpbuf, 0, sizeof(tmpbuf));
00261         return PXE_PGP_CORRUPT_DATA;
00262     }
00263 
00264     if (buf[len - 2] != buf[len] || buf[len - 1] != buf[len + 1])
00265     {
00266         px_debug("prefix_init: corrupt prefix");
00267 
00268         /*
00269          * The original purpose of the 2-byte check was to show user a
00270          * friendly "wrong key" message. This made following possible:
00271          *
00272          * "An Attack on CFB Mode Encryption As Used By OpenPGP" by Serge
00273          * Mister and Robert Zuccherato
00274          *
00275          * To avoid being 'oracle', we delay reporting, which basically means
00276          * we prefer to run into corrupt packet header.
00277          *
00278          * We _could_ throw PXE_PGP_CORRUPT_DATA here, but there is
00279          * possibility of attack via timing, so we don't.
00280          */
00281         ctx->corrupt_prefix = 1;
00282     }
00283     memset(tmpbuf, 0, sizeof(tmpbuf));
00284     return 0;
00285 }
00286 
00287 static struct PullFilterOps prefix_filter = {
00288     prefix_init, NULL, NULL
00289 };
00290 
00291 
00292 /*
00293  * Decrypt filter
00294  */
00295 
00296 static int
00297 decrypt_init(void **priv_p, void *arg, PullFilter *src)
00298 {
00299     PGP_CFB    *cfb = arg;
00300 
00301     *priv_p = cfb;
00302 
00303     /* we need to write somewhere, so ask for a buffer */
00304     return 4096;
00305 }
00306 
00307 static int
00308 decrypt_read(void *priv, PullFilter *src, int len,
00309              uint8 **data_p, uint8 *buf, int buflen)
00310 {
00311     PGP_CFB    *cfb = priv;
00312     uint8      *tmp;
00313     int         res;
00314 
00315     res = pullf_read(src, len, &tmp);
00316     if (res > 0)
00317     {
00318         pgp_cfb_decrypt(cfb, tmp, res, buf);
00319         *data_p = buf;
00320     }
00321     return res;
00322 }
00323 
00324 struct PullFilterOps pgp_decrypt_filter = {
00325     decrypt_init, decrypt_read, NULL
00326 };
00327 
00328 
00329 /*
00330  * MDC hasher filter
00331  */
00332 
00333 static int
00334 mdc_init(void **priv_p, void *arg, PullFilter *src)
00335 {
00336     PGP_Context *ctx = arg;
00337 
00338     *priv_p = ctx;
00339     return pgp_load_digest(PGP_DIGEST_SHA1, &ctx->mdc_ctx);
00340 }
00341 
00342 static void
00343 mdc_free(void *priv)
00344 {
00345     PGP_Context *ctx = priv;
00346 
00347     if (ctx->use_mdcbuf_filter)
00348         return;
00349     px_md_free(ctx->mdc_ctx);
00350     ctx->mdc_ctx = NULL;
00351 }
00352 
00353 static int
00354 mdc_finish(PGP_Context *ctx, PullFilter *src,
00355            int len, uint8 **data_p)
00356 {
00357     int         res;
00358     uint8       hash[20];
00359     uint8       tmpbuf[22];
00360 
00361     if (len + 1 > sizeof(tmpbuf))
00362         return PXE_BUG;
00363 
00364     /* read data */
00365     res = pullf_read_max(src, len + 1, data_p, tmpbuf);
00366     if (res < 0)
00367         return res;
00368     if (res == 0)
00369     {
00370         if (ctx->mdc_checked == 0)
00371         {
00372             px_debug("no mdc");
00373             return PXE_PGP_CORRUPT_DATA;
00374         }
00375         return 0;
00376     }
00377 
00378     /* safety check */
00379     if (ctx->in_mdc_pkt > 1)
00380     {
00381         px_debug("mdc_finish: several times here?");
00382         return PXE_PGP_CORRUPT_DATA;
00383     }
00384     ctx->in_mdc_pkt++;
00385 
00386     /* is the packet sane? */
00387     if (res != 20)
00388     {
00389         px_debug("mdc_finish: read failed, res=%d", res);
00390         return PXE_PGP_CORRUPT_DATA;
00391     }
00392 
00393     /*
00394      * ok, we got the hash, now check
00395      */
00396     px_md_finish(ctx->mdc_ctx, hash);
00397     res = memcmp(hash, *data_p, 20);
00398     memset(hash, 0, 20);
00399     memset(tmpbuf, 0, sizeof(tmpbuf));
00400     if (res != 0)
00401     {
00402         px_debug("mdc_finish: mdc failed");
00403         return PXE_PGP_CORRUPT_DATA;
00404     }
00405     ctx->mdc_checked = 1;
00406     return len;
00407 }
00408 
00409 static int
00410 mdc_read(void *priv, PullFilter *src, int len,
00411          uint8 **data_p, uint8 *buf, int buflen)
00412 {
00413     int         res;
00414     PGP_Context *ctx = priv;
00415 
00416     /* skip this filter? */
00417     if (ctx->use_mdcbuf_filter)
00418         return pullf_read(src, len, data_p);
00419 
00420     if (ctx->in_mdc_pkt)
00421         return mdc_finish(ctx, src, len, data_p);
00422 
00423     res = pullf_read(src, len, data_p);
00424     if (res < 0)
00425         return res;
00426     if (res == 0)
00427     {
00428         px_debug("mdc_read: unexpected eof");
00429         return PXE_PGP_CORRUPT_DATA;
00430     }
00431     px_md_update(ctx->mdc_ctx, *data_p, res);
00432 
00433     return res;
00434 }
00435 
00436 static struct PullFilterOps mdc_filter = {
00437     mdc_init, mdc_read, mdc_free
00438 };
00439 
00440 
00441 /*
00442  * Combined Pkt reader and MDC hasher.
00443  *
00444  * For the case of SYMENCRYPTED_MDC packet, where
00445  * the data part has 'context length', which means
00446  * that data packet ends 22 bytes before end of parent
00447  * packet, which is silly.
00448  */
00449 #define MDCBUF_LEN 8192
00450 struct MDCBufData
00451 {
00452     PGP_Context *ctx;
00453     int         eof;
00454     int         buflen;
00455     int         avail;
00456     uint8      *pos;
00457     int         mdc_avail;
00458     uint8       mdc_buf[22];
00459     uint8       buf[MDCBUF_LEN];
00460 };
00461 
00462 static int
00463 mdcbuf_init(void **priv_p, void *arg, PullFilter *src)
00464 {
00465     PGP_Context *ctx = arg;
00466     struct MDCBufData *st;
00467 
00468     st = px_alloc(sizeof(*st));
00469     memset(st, 0, sizeof(*st));
00470     st->buflen = sizeof(st->buf);
00471     st->ctx = ctx;
00472     *priv_p = st;
00473 
00474     /* take over the work of mdc_filter */
00475     ctx->use_mdcbuf_filter = 1;
00476 
00477     return 0;
00478 }
00479 
00480 static int
00481 mdcbuf_finish(struct MDCBufData * st)
00482 {
00483     uint8       hash[20];
00484     int         res;
00485 
00486     st->eof = 1;
00487 
00488     if (st->mdc_buf[0] != 0xD3 || st->mdc_buf[1] != 0x14)
00489     {
00490         px_debug("mdcbuf_finish: bad MDC pkt hdr");
00491         return PXE_PGP_CORRUPT_DATA;
00492     }
00493     px_md_update(st->ctx->mdc_ctx, st->mdc_buf, 2);
00494     px_md_finish(st->ctx->mdc_ctx, hash);
00495     res = memcmp(hash, st->mdc_buf + 2, 20);
00496     memset(hash, 0, 20);
00497     if (res)
00498     {
00499         px_debug("mdcbuf_finish: MDC does not match");
00500         res = PXE_PGP_CORRUPT_DATA;
00501     }
00502     return res;
00503 }
00504 
00505 static void
00506 mdcbuf_load_data(struct MDCBufData * st, uint8 *src, int len)
00507 {
00508     uint8      *dst = st->pos + st->avail;
00509 
00510     memcpy(dst, src, len);
00511     px_md_update(st->ctx->mdc_ctx, src, len);
00512     st->avail += len;
00513 }
00514 
00515 static void
00516 mdcbuf_load_mdc(struct MDCBufData * st, uint8 *src, int len)
00517 {
00518     memmove(st->mdc_buf + st->mdc_avail, src, len);
00519     st->mdc_avail += len;
00520 }
00521 
00522 static int
00523 mdcbuf_refill(struct MDCBufData * st, PullFilter *src)
00524 {
00525     uint8      *data;
00526     int         res;
00527     int         need;
00528 
00529     /* put avail data in start */
00530     if (st->avail > 0 && st->pos != st->buf)
00531         memmove(st->buf, st->pos, st->avail);
00532     st->pos = st->buf;
00533 
00534     /* read new data */
00535     need = st->buflen + 22 - st->avail - st->mdc_avail;
00536     res = pullf_read(src, need, &data);
00537     if (res < 0)
00538         return res;
00539     if (res == 0)
00540         return mdcbuf_finish(st);
00541 
00542     /* add to buffer */
00543     if (res >= 22)
00544     {
00545         mdcbuf_load_data(st, st->mdc_buf, st->mdc_avail);
00546         st->mdc_avail = 0;
00547 
00548         mdcbuf_load_data(st, data, res - 22);
00549         mdcbuf_load_mdc(st, data + res - 22, 22);
00550     }
00551     else
00552     {
00553         int         canmove = st->mdc_avail + res - 22;
00554 
00555         if (canmove > 0)
00556         {
00557             mdcbuf_load_data(st, st->mdc_buf, canmove);
00558             st->mdc_avail -= canmove;
00559             memmove(st->mdc_buf, st->mdc_buf + canmove, st->mdc_avail);
00560         }
00561         mdcbuf_load_mdc(st, data, res);
00562     }
00563     return 0;
00564 }
00565 
00566 static int
00567 mdcbuf_read(void *priv, PullFilter *src, int len,
00568             uint8 **data_p, uint8 *buf, int buflen)
00569 {
00570     struct MDCBufData *st = priv;
00571     int         res;
00572 
00573     if (!st->eof && len > st->avail)
00574     {
00575         res = mdcbuf_refill(st, src);
00576         if (res < 0)
00577             return res;
00578     }
00579 
00580     if (len > st->avail)
00581         len = st->avail;
00582 
00583     *data_p = st->pos;
00584     st->pos += len;
00585     st->avail -= len;
00586     return len;
00587 }
00588 
00589 static void
00590 mdcbuf_free(void *priv)
00591 {
00592     struct MDCBufData *st = priv;
00593 
00594     px_md_free(st->ctx->mdc_ctx);
00595     st->ctx->mdc_ctx = NULL;
00596     memset(st, 0, sizeof(*st));
00597     px_free(st);
00598 }
00599 
00600 static struct PullFilterOps mdcbuf_filter = {
00601     mdcbuf_init, mdcbuf_read, mdcbuf_free
00602 };
00603 
00604 
00605 /*
00606  * Decrypt separate session key
00607  */
00608 static int
00609 decrypt_key(PGP_Context *ctx, const uint8 *src, int len)
00610 {
00611     int         res;
00612     uint8       algo;
00613     PGP_CFB    *cfb;
00614 
00615     res = pgp_cfb_create(&cfb, ctx->s2k_cipher_algo,
00616                          ctx->s2k.key, ctx->s2k.key_len, 0, NULL);
00617     if (res < 0)
00618         return res;
00619 
00620     pgp_cfb_decrypt(cfb, src, 1, &algo);
00621     src++;
00622     len--;
00623 
00624     pgp_cfb_decrypt(cfb, src, len, ctx->sess_key);
00625     pgp_cfb_free(cfb);
00626     ctx->sess_key_len = len;
00627     ctx->cipher_algo = algo;
00628 
00629     if (pgp_get_cipher_key_size(algo) != len)
00630     {
00631         px_debug("sesskey bad len: algo=%d, expected=%d, got=%d",
00632                  algo, pgp_get_cipher_key_size(algo), len);
00633         return PXE_PGP_CORRUPT_DATA;
00634     }
00635     return 0;
00636 }
00637 
00638 /*
00639  * Handle key packet
00640  */
00641 static int
00642 parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src)
00643 {
00644     uint8      *p;
00645     int         res;
00646     uint8       tmpbuf[PGP_MAX_KEY + 2];
00647     uint8       ver;
00648 
00649     GETBYTE(src, ver);
00650     GETBYTE(src, ctx->s2k_cipher_algo);
00651     if (ver != 4)
00652     {
00653         px_debug("bad key pkt ver");
00654         return PXE_PGP_CORRUPT_DATA;
00655     }
00656 
00657     /*
00658      * read S2K info
00659      */
00660     res = pgp_s2k_read(src, &ctx->s2k);
00661     if (res < 0)
00662         return res;
00663     ctx->s2k_mode = ctx->s2k.mode;
00664     ctx->s2k_digest_algo = ctx->s2k.digest_algo;
00665 
00666     /*
00667      * generate key from password
00668      */
00669     res = pgp_s2k_process(&ctx->s2k, ctx->s2k_cipher_algo,
00670                           ctx->sym_key, ctx->sym_key_len);
00671     if (res < 0)
00672         return res;
00673 
00674     /*
00675      * do we have separate session key?
00676      */
00677     res = pullf_read_max(src, PGP_MAX_KEY + 2, &p, tmpbuf);
00678     if (res < 0)
00679         return res;
00680 
00681     if (res == 0)
00682     {
00683         /*
00684          * no, s2k key is session key
00685          */
00686         memcpy(ctx->sess_key, ctx->s2k.key, ctx->s2k.key_len);
00687         ctx->sess_key_len = ctx->s2k.key_len;
00688         ctx->cipher_algo = ctx->s2k_cipher_algo;
00689         res = 0;
00690         ctx->use_sess_key = 0;
00691     }
00692     else
00693     {
00694         /*
00695          * yes, decrypt it
00696          */
00697         if (res < 17 || res > PGP_MAX_KEY + 1)
00698         {
00699             px_debug("expect key, but bad data");
00700             return PXE_PGP_CORRUPT_DATA;
00701         }
00702         ctx->use_sess_key = 1;
00703         res = decrypt_key(ctx, p, res);
00704     }
00705 
00706     memset(tmpbuf, 0, sizeof(tmpbuf));
00707     return res;
00708 }
00709 
00710 static int
00711 copy_crlf(MBuf *dst, uint8 *data, int len, int *got_cr)
00712 {
00713     uint8      *data_end = data + len;
00714     uint8       tmpbuf[1024];
00715     uint8      *tmp_end = tmpbuf + sizeof(tmpbuf);
00716     uint8      *p;
00717     int         res;
00718 
00719     p = tmpbuf;
00720     if (*got_cr)
00721     {
00722         if (*data != '\n')
00723             *p++ = '\r';
00724         *got_cr = 0;
00725     }
00726     while (data < data_end)
00727     {
00728         if (*data == '\r')
00729         {
00730             if (data + 1 < data_end)
00731             {
00732                 if (*(data + 1) == '\n')
00733                     data++;
00734             }
00735             else
00736             {
00737                 *got_cr = 1;
00738                 break;
00739             }
00740         }
00741         *p++ = *data++;
00742         if (p >= tmp_end)
00743         {
00744             res = mbuf_append(dst, tmpbuf, p - tmpbuf);
00745             if (res < 0)
00746                 return res;
00747             p = tmpbuf;
00748         }
00749     }
00750     if (p - tmpbuf > 0)
00751     {
00752         res = mbuf_append(dst, tmpbuf, p - tmpbuf);
00753         if (res < 0)
00754             return res;
00755     }
00756     return 0;
00757 }
00758 
00759 static int
00760 parse_literal_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
00761 {
00762     int         type;
00763     int         name_len;
00764     int         res;
00765     uint8      *buf;
00766     uint8       tmpbuf[4];
00767     int         got_cr = 0;
00768 
00769     GETBYTE(pkt, type);
00770     GETBYTE(pkt, name_len);
00771 
00772     /* skip name */
00773     while (name_len > 0)
00774     {
00775         res = pullf_read(pkt, name_len, &buf);
00776         if (res < 0)
00777             return res;
00778         if (res == 0)
00779             break;
00780         name_len -= res;
00781     }
00782     if (name_len > 0)
00783     {
00784         px_debug("parse_literal_data: unexpected eof");
00785         return PXE_PGP_CORRUPT_DATA;
00786     }
00787 
00788     /* skip date */
00789     res = pullf_read_max(pkt, 4, &buf, tmpbuf);
00790     if (res != 4)
00791     {
00792         px_debug("parse_literal_data: unexpected eof");
00793         return PXE_PGP_CORRUPT_DATA;
00794     }
00795     memset(tmpbuf, 0, 4);
00796 
00797     /* check if text */
00798     if (ctx->text_mode)
00799         if (type != 't' && type != 'u')
00800         {
00801             px_debug("parse_literal_data: data type=%c", type);
00802             return PXE_PGP_NOT_TEXT;
00803         }
00804 
00805     ctx->unicode_mode = (type == 'u') ? 1 : 0;
00806 
00807     /* read data */
00808     while (1)
00809     {
00810         res = pullf_read(pkt, 32 * 1024, &buf);
00811         if (res <= 0)
00812             break;
00813 
00814         if (ctx->text_mode && ctx->convert_crlf)
00815             res = copy_crlf(dst, buf, res, &got_cr);
00816         else
00817             res = mbuf_append(dst, buf, res);
00818         if (res < 0)
00819             break;
00820     }
00821     if (res >= 0 && got_cr)
00822         res = mbuf_append(dst, (const uint8 *) "\r", 1);
00823     return res;
00824 }
00825 
00826 /* process_data_packets and parse_compressed_data call each other */
00827 static int process_data_packets(PGP_Context *ctx, MBuf *dst,
00828                      PullFilter *src, int allow_compr, int need_mdc);
00829 
00830 static int
00831 parse_compressed_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
00832 {
00833     int         res;
00834     uint8       type;
00835     PullFilter *pf_decompr;
00836 
00837     GETBYTE(pkt, type);
00838 
00839     ctx->compress_algo = type;
00840     switch (type)
00841     {
00842         case PGP_COMPR_NONE:
00843             res = process_data_packets(ctx, dst, pkt, NO_COMPR, NO_MDC);
00844             break;
00845 
00846         case PGP_COMPR_ZIP:
00847         case PGP_COMPR_ZLIB:
00848             res = pgp_decompress_filter(&pf_decompr, ctx, pkt);
00849             if (res >= 0)
00850             {
00851                 res = process_data_packets(ctx, dst, pf_decompr,
00852                                            NO_COMPR, NO_MDC);
00853                 pullf_free(pf_decompr);
00854             }
00855             break;
00856 
00857         case PGP_COMPR_BZIP2:
00858             px_debug("parse_compressed_data: bzip2 unsupported");
00859             res = PXE_PGP_UNSUPPORTED_COMPR;
00860             break;
00861 
00862         default:
00863             px_debug("parse_compressed_data: unknown compr type");
00864             res = PXE_PGP_CORRUPT_DATA;
00865     }
00866 
00867     return res;
00868 }
00869 
00870 static int
00871 process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
00872                      int allow_compr, int need_mdc)
00873 {
00874     uint8       tag;
00875     int         len,
00876                 res;
00877     int         got_data = 0;
00878     int         got_mdc = 0;
00879     PullFilter *pkt = NULL;
00880     uint8      *tmp;
00881 
00882     while (1)
00883     {
00884         res = pgp_parse_pkt_hdr(src, &tag, &len, ALLOW_CTX_SIZE);
00885         if (res <= 0)
00886             break;
00887 
00888 
00889         /* mdc packet should be last */
00890         if (got_mdc)
00891         {
00892             px_debug("process_data_packets: data after mdc");
00893             res = PXE_PGP_CORRUPT_DATA;
00894             break;
00895         }
00896 
00897         /* context length inside SYMENC_MDC needs special handling */
00898         if (need_mdc && res == PKT_CONTEXT)
00899             res = pullf_create(&pkt, &mdcbuf_filter, ctx, src);
00900         else
00901             res = pgp_create_pkt_reader(&pkt, src, len, res, ctx);
00902         if (res < 0)
00903             break;
00904 
00905         switch (tag)
00906         {
00907             case PGP_PKT_LITERAL_DATA:
00908                 got_data = 1;
00909                 res = parse_literal_data(ctx, dst, pkt);
00910                 break;
00911             case PGP_PKT_COMPRESSED_DATA:
00912                 if (allow_compr == 0)
00913                 {
00914                     px_debug("process_data_packets: unexpected compression");
00915                     res = PXE_PGP_CORRUPT_DATA;
00916                 }
00917                 else if (got_data)
00918                 {
00919                     /*
00920                      * compr data must be alone
00921                      */
00922                     px_debug("process_data_packets: only one cmpr pkt allowed");
00923                     res = PXE_PGP_CORRUPT_DATA;
00924                 }
00925                 else
00926                 {
00927                     got_data = 1;
00928                     res = parse_compressed_data(ctx, dst, pkt);
00929                 }
00930                 break;
00931             case PGP_PKT_MDC:
00932                 if (need_mdc == NO_MDC)
00933                 {
00934                     px_debug("process_data_packets: unexpected MDC");
00935                     res = PXE_PGP_CORRUPT_DATA;
00936                     break;
00937                 }
00938 
00939                 /* notify mdc_filter */
00940                 ctx->in_mdc_pkt = 1;
00941 
00942                 res = pullf_read(pkt, 8192, &tmp);
00943                 if (res > 0)
00944                     got_mdc = 1;
00945                 break;
00946             default:
00947                 px_debug("process_data_packets: unexpected pkt tag=%d", tag);
00948                 res = PXE_PGP_CORRUPT_DATA;
00949         }
00950 
00951         pullf_free(pkt);
00952         pkt = NULL;
00953 
00954         if (res < 0)
00955             break;
00956     }
00957 
00958     if (pkt)
00959         pullf_free(pkt);
00960 
00961     if (res < 0)
00962         return res;
00963 
00964     if (!got_data)
00965     {
00966         px_debug("process_data_packets: no data");
00967         res = PXE_PGP_CORRUPT_DATA;
00968     }
00969     if (need_mdc && !got_mdc && !ctx->use_mdcbuf_filter)
00970     {
00971         px_debug("process_data_packets: got no mdc");
00972         res = PXE_PGP_CORRUPT_DATA;
00973     }
00974     return res;
00975 }
00976 
00977 static int
00978 parse_symenc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
00979 {
00980     int         res;
00981     PGP_CFB    *cfb = NULL;
00982     PullFilter *pf_decrypt = NULL;
00983     PullFilter *pf_prefix = NULL;
00984 
00985     res = pgp_cfb_create(&cfb, ctx->cipher_algo,
00986                          ctx->sess_key, ctx->sess_key_len, 1, NULL);
00987     if (res < 0)
00988         goto out;
00989 
00990     res = pullf_create(&pf_decrypt, &pgp_decrypt_filter, cfb, pkt);
00991     if (res < 0)
00992         goto out;
00993 
00994     res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_decrypt);
00995     if (res < 0)
00996         goto out;
00997 
00998     res = process_data_packets(ctx, dst, pf_prefix, ALLOW_COMPR, NO_MDC);
00999 
01000 out:
01001     if (pf_prefix)
01002         pullf_free(pf_prefix);
01003     if (pf_decrypt)
01004         pullf_free(pf_decrypt);
01005     if (cfb)
01006         pgp_cfb_free(cfb);
01007 
01008     return res;
01009 }
01010 
01011 static int
01012 parse_symenc_mdc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
01013 {
01014     int         res;
01015     PGP_CFB    *cfb = NULL;
01016     PullFilter *pf_decrypt = NULL;
01017     PullFilter *pf_prefix = NULL;
01018     PullFilter *pf_mdc = NULL;
01019     uint8       ver;
01020 
01021     GETBYTE(pkt, ver);
01022     if (ver != 1)
01023     {
01024         px_debug("parse_symenc_mdc_data: pkt ver != 1");
01025         return PXE_PGP_CORRUPT_DATA;
01026     }
01027 
01028     res = pgp_cfb_create(&cfb, ctx->cipher_algo,
01029                          ctx->sess_key, ctx->sess_key_len, 0, NULL);
01030     if (res < 0)
01031         goto out;
01032 
01033     res = pullf_create(&pf_decrypt, &pgp_decrypt_filter, cfb, pkt);
01034     if (res < 0)
01035         goto out;
01036 
01037     res = pullf_create(&pf_mdc, &mdc_filter, ctx, pf_decrypt);
01038     if (res < 0)
01039         goto out;
01040 
01041     res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_mdc);
01042     if (res < 0)
01043         goto out;
01044 
01045     res = process_data_packets(ctx, dst, pf_prefix, ALLOW_COMPR, NEED_MDC);
01046 
01047 out:
01048     if (pf_prefix)
01049         pullf_free(pf_prefix);
01050     if (pf_mdc)
01051         pullf_free(pf_mdc);
01052     if (pf_decrypt)
01053         pullf_free(pf_decrypt);
01054     if (cfb)
01055         pgp_cfb_free(cfb);
01056 
01057     return res;
01058 }
01059 
01060 /*
01061  * skip over packet contents
01062  */
01063 int
01064 pgp_skip_packet(PullFilter *pkt)
01065 {
01066     int         res = 1;
01067     uint8      *tmp;
01068 
01069     while (res > 0)
01070         res = pullf_read(pkt, 32 * 1024, &tmp);
01071     return res < 0 ? res : 0;
01072 }
01073 
01074 /*
01075  * expect to be at packet end, any data is error
01076  */
01077 int
01078 pgp_expect_packet_end(PullFilter *pkt)
01079 {
01080     int         res = 1;
01081     uint8      *tmp;
01082 
01083     while (res > 0)
01084     {
01085         res = pullf_read(pkt, 32 * 1024, &tmp);
01086         if (res > 0)
01087         {
01088             px_debug("pgp_expect_packet_end: got data");
01089             return PXE_PGP_CORRUPT_DATA;
01090         }
01091     }
01092     return res < 0 ? res : 0;
01093 }
01094 
01095 int
01096 pgp_decrypt(PGP_Context *ctx, MBuf *msrc, MBuf *mdst)
01097 {
01098     int         res;
01099     PullFilter *src = NULL;
01100     PullFilter *pkt = NULL;
01101     uint8       tag;
01102     int         len;
01103     int         got_key = 0;
01104     int         got_data = 0;
01105 
01106     res = pullf_create_mbuf_reader(&src, msrc);
01107 
01108     while (res >= 0)
01109     {
01110         res = pgp_parse_pkt_hdr(src, &tag, &len, NO_CTX_SIZE);
01111         if (res <= 0)
01112             break;
01113 
01114         res = pgp_create_pkt_reader(&pkt, src, len, res, ctx);
01115         if (res < 0)
01116             break;
01117 
01118         res = PXE_PGP_CORRUPT_DATA;
01119         switch (tag)
01120         {
01121             case PGP_PKT_MARKER:
01122                 res = pgp_skip_packet(pkt);
01123                 break;
01124             case PGP_PKT_PUBENCRYPTED_SESSKEY:
01125                 /* fixme: skip those */
01126                 res = pgp_parse_pubenc_sesskey(ctx, pkt);
01127                 got_key = 1;
01128                 break;
01129             case PGP_PKT_SYMENCRYPTED_SESSKEY:
01130                 if (got_key)
01131 
01132                     /*
01133                      * Theoretically, there could be several keys, both public
01134                      * and symmetric, all of which encrypt same session key.
01135                      * Decrypt should try with each one, before failing.
01136                      */
01137                     px_debug("pgp_decrypt: using first of several keys");
01138                 else
01139                 {
01140                     got_key = 1;
01141                     res = parse_symenc_sesskey(ctx, pkt);
01142                 }
01143                 break;
01144             case PGP_PKT_SYMENCRYPTED_DATA:
01145                 if (!got_key)
01146                     px_debug("pgp_decrypt: have data but no key");
01147                 else if (got_data)
01148                     px_debug("pgp_decrypt: got second data packet");
01149                 else
01150                 {
01151                     got_data = 1;
01152                     ctx->disable_mdc = 1;
01153                     res = parse_symenc_data(ctx, pkt, mdst);
01154                 }
01155                 break;
01156             case PGP_PKT_SYMENCRYPTED_DATA_MDC:
01157                 if (!got_key)
01158                     px_debug("pgp_decrypt: have data but no key");
01159                 else if (got_data)
01160                     px_debug("pgp_decrypt: several data pkts not supported");
01161                 else
01162                 {
01163                     got_data = 1;
01164                     ctx->disable_mdc = 0;
01165                     res = parse_symenc_mdc_data(ctx, pkt, mdst);
01166                 }
01167                 break;
01168             default:
01169                 px_debug("pgp_decrypt: unknown tag: 0x%02x", tag);
01170         }
01171         pullf_free(pkt);
01172         pkt = NULL;
01173     }
01174 
01175     if (pkt)
01176         pullf_free(pkt);
01177 
01178     if (src)
01179         pullf_free(src);
01180 
01181     if (res < 0)
01182         return res;
01183 
01184     if (!got_data || ctx->corrupt_prefix)
01185         res = PXE_PGP_CORRUPT_DATA;
01186 
01187     return res;
01188 }