Age Owner Branch data TLA 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
5421 bruce@momjian.us 52 :CBC 268 : parse_new_len(PullFilter *src, int *len_p)
53 : : {
54 : : uint8 b;
55 : : int len;
6853 56 : 268 : int pkttype = PKT_NORMAL;
57 : :
58 [ - + ]: 268 : GETBYTE(src, b);
59 [ + + ]: 268 : if (b <= 191)
60 : 244 : len = b;
61 [ + - + + ]: 24 : else if (b >= 192 && b <= 223)
62 : : {
63 : 8 : len = ((unsigned) (b) - 192) << 8;
64 [ - + ]: 8 : GETBYTE(src, b);
65 : 8 : len += 192 + b;
66 : : }
67 [ + + ]: 16 : else if (b == 255)
68 : : {
69 [ - + ]: 1 : GETBYTE(src, b);
70 : 1 : len = b;
71 [ - + ]: 1 : GETBYTE(src, b);
72 : 1 : len = (len << 8) | b;
73 [ - + ]: 1 : GETBYTE(src, b);
74 : 1 : len = (len << 8) | b;
75 [ - + ]: 1 : GETBYTE(src, b);
76 : 1 : len = (len << 8) | b;
77 : : }
78 : : else
79 : : {
80 : 15 : len = 1 << (b & 0x1F);
81 : 15 : pkttype = PKT_STREAM;
82 : : }
83 : :
84 [ + - - + ]: 268 : if (len < 0 || len > MAX_CHUNK)
85 : : {
6853 bruce@momjian.us 86 :UBC 0 : px_debug("parse_new_len: weird length");
87 : 0 : return PXE_PGP_CORRUPT_DATA;
88 : : }
89 : :
6853 bruce@momjian.us 90 :CBC 268 : *len_p = len;
91 : 268 : return pkttype;
92 : : }
93 : :
94 : : static int
5421 95 : 213 : parse_old_len(PullFilter *src, int *len_p, int lentype)
96 : : {
97 : : uint8 b;
98 : : int len;
99 : :
6853 100 [ - + ]: 213 : GETBYTE(src, b);
101 : 213 : len = b;
102 : :
103 [ + + ]: 213 : if (lentype == 1)
104 : : {
105 [ - + ]: 102 : GETBYTE(src, b);
106 : 102 : len = (len << 8) | b;
107 : : }
108 [ - + ]: 111 : else if (lentype == 2)
109 : : {
6853 bruce@momjian.us 110 [ # # ]:UBC 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 : :
6853 bruce@momjian.us 118 [ + - - + ]:CBC 213 : if (len < 0 || len > MAX_CHUNK)
119 : : {
6853 bruce@momjian.us 120 :UBC 0 : px_debug("parse_old_len: weird length");
121 : 0 : return PXE_PGP_CORRUPT_DATA;
122 : : }
6853 bruce@momjian.us 123 :CBC 213 : *len_p = len;
124 : 213 : return PKT_NORMAL;
125 : : }
126 : :
127 : : /* returns pkttype or 0 on eof */
128 : : int
5421 129 : 645 : 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 */
6853 136 : 645 : res = pullf_read(src, 1, &p);
137 [ - + ]: 645 : if (res < 0)
6853 bruce@momjian.us 138 :UBC 0 : return res;
6853 bruce@momjian.us 139 [ + + ]:CBC 645 : if (res == 0)
140 : 172 : return 0;
141 : :
142 [ + + ]: 473 : if ((*p & 0x80) == 0)
143 : : {
144 : 2 : px_debug("pgp_parse_pkt_hdr: not pkt hdr");
145 : 2 : return PXE_PGP_CORRUPT_DATA;
146 : : }
147 : :
148 [ + + ]: 471 : if (*p & 0x40)
149 : : {
150 : 255 : *tag = *p & 0x3f;
151 : 255 : res = parse_new_len(src, len_p);
152 : : }
153 : : else
154 : : {
155 : 216 : lentype = *p & 3;
156 : 216 : *tag = (*p >> 2) & 0x0F;
157 [ + + ]: 216 : if (lentype == 3)
158 [ + - ]: 3 : res = allow_ctx ? PKT_CONTEXT : PXE_PGP_CORRUPT_DATA;
159 : : else
160 : 213 : res = parse_old_len(src, len_p, lentype);
161 : : }
162 : 471 : return res;
163 : : }
164 : :
165 : : /*
166 : : * Packet reader
167 : : */
168 : : struct PktData
169 : : {
170 : : int type;
171 : : int len;
172 : : };
173 : :
174 : : static int
5421 175 : 2542 : pktreader_pull(void *priv, PullFilter *src, int len,
176 : : uint8 **data_p, uint8 *buf, int buflen)
177 : : {
178 : : int res;
6853 179 : 2542 : struct PktData *pkt = priv;
180 : :
181 : : /* PKT_CONTEXT means: whatever there is */
182 [ - + ]: 2542 : if (pkt->type == PKT_CONTEXT)
6853 bruce@momjian.us 183 :UBC 0 : return pullf_read(src, len, data_p);
184 : :
3442 tgl@sss.pgh.pa.us 185 [ + + ]:CBC 2555 : while (pkt->len == 0)
186 : : {
187 : : /* this was last chunk in stream */
6853 bruce@momjian.us 188 [ + + ]: 400 : if (pkt->type == PKT_NORMAL)
189 : 387 : return 0;
190 : :
191 : : /* next chunk in stream */
192 : 13 : res = parse_new_len(src, &pkt->len);
193 [ - + ]: 13 : if (res < 0)
6853 bruce@momjian.us 194 :UBC 0 : return res;
6853 bruce@momjian.us 195 :CBC 13 : pkt->type = res;
196 : : }
197 : :
198 [ + + ]: 2155 : if (len > pkt->len)
199 : 263 : len = pkt->len;
200 : :
201 : 2155 : res = pullf_read(src, len, data_p);
202 [ + - ]: 2155 : if (res > 0)
203 : 2155 : pkt->len -= res;
204 : :
205 : 2155 : return res;
206 : : }
207 : :
208 : : static void
209 : 468 : pktreader_free(void *priv)
210 : : {
211 : 468 : struct PktData *pkt = priv;
212 : :
3650 213 : 468 : px_memset(pkt, 0, sizeof(*pkt));
1297 michael@paquier.xyz 214 : 468 : pfree(pkt);
6853 bruce@momjian.us 215 : 468 : }
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
5421 223 : 468 : pgp_create_pkt_reader(PullFilter **pf_p, PullFilter *src, int len,
224 : : int pkttype, PGP_Context *ctx)
225 : : {
226 : : int res;
1297 michael@paquier.xyz 227 : 468 : struct PktData *pkt = palloc(sizeof(*pkt));
228 : :
6853 bruce@momjian.us 229 : 468 : pkt->type = pkttype;
230 : 468 : pkt->len = len;
231 : 468 : res = pullf_create(pf_p, &pktreader_filter, pkt, src);
232 [ - + ]: 468 : if (res < 0)
1297 michael@paquier.xyz 233 :UBC 0 : pfree(pkt);
6853 bruce@momjian.us 234 :CBC 468 : 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
5421 244 : 72 : prefix_init(void **priv_p, void *arg, PullFilter *src)
245 : : {
6853 246 : 72 : PGP_Context *ctx = arg;
247 : : int len;
248 : : int res;
249 : : uint8 *buf;
250 : : uint8 tmpbuf[PGP_MAX_BLOCK + 2];
251 : :
252 : 72 : len = pgp_get_cipher_block_size(ctx->cipher_algo);
253 : : /* Make sure we have space for prefix */
75 dgustafsson@postgres 254 [ - + ]: 72 : if (len > PGP_MAX_BLOCK)
6853 bruce@momjian.us 255 :UBC 0 : return PXE_BUG;
256 : :
6853 bruce@momjian.us 257 :CBC 72 : res = pullf_read_max(src, len + 2, &buf, tmpbuf);
258 [ - + ]: 72 : if (res < 0)
6853 bruce@momjian.us 259 :UBC 0 : return res;
6853 bruce@momjian.us 260 [ - + ]:CBC 72 : if (res != len + 2)
261 : : {
6853 bruce@momjian.us 262 :UBC 0 : px_debug("prefix_init: short read");
3650 263 : 0 : px_memset(tmpbuf, 0, sizeof(tmpbuf));
6853 264 : 0 : return PXE_PGP_CORRUPT_DATA;
265 : : }
266 : :
6853 bruce@momjian.us 267 [ + + - + ]:CBC 72 : 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 : : }
3650 273 : 72 : px_memset(tmpbuf, 0, sizeof(tmpbuf));
6853 274 : 72 : 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
5421 287 : 76 : decrypt_init(void **priv_p, void *arg, PullFilter *src)
288 : : {
6756 289 : 76 : PGP_CFB *cfb = arg;
290 : :
6853 291 : 76 : *priv_p = cfb;
292 : :
293 : : /* we need to write somewhere, so ask for a buffer */
294 : 76 : return 4096;
295 : : }
296 : :
297 : : static int
5421 298 : 804 : decrypt_read(void *priv, PullFilter *src, int len,
299 : : uint8 **data_p, uint8 *buf, int buflen)
300 : : {
6756 301 : 804 : PGP_CFB *cfb = priv;
302 : : uint8 *tmp;
303 : : int res;
304 : :
6853 305 : 804 : res = pullf_read(src, len, &tmp);
6756 306 [ + + ]: 804 : if (res > 0)
307 : : {
6853 308 : 730 : pgp_cfb_decrypt(cfb, tmp, res, buf);
309 : 730 : *data_p = buf;
310 : : }
311 : 804 : 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
5421 324 : 70 : mdc_init(void **priv_p, void *arg, PullFilter *src)
325 : : {
6853 326 : 70 : PGP_Context *ctx = arg;
327 : :
328 : 70 : *priv_p = ctx;
329 : 70 : return pgp_load_digest(PGP_DIGEST_SHA1, &ctx->mdc_ctx);
330 : : }
331 : :
332 : : static void
6756 333 : 70 : mdc_free(void *priv)
334 : : {
6853 335 : 70 : PGP_Context *ctx = priv;
336 : :
337 [ + + ]: 70 : if (ctx->use_mdcbuf_filter)
338 : 3 : return;
339 : 67 : px_md_free(ctx->mdc_ctx);
340 : 67 : ctx->mdc_ctx = NULL;
341 : : }
342 : :
343 : : static int
3362 tgl@sss.pgh.pa.us 344 : 64 : 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 [ - + ]: 64 : if (ctx->use_mdcbuf_filter)
6853 bruce@momjian.us 353 :UBC 0 : return PXE_BUG;
354 : :
355 : : /* It's SHA1 */
3362 tgl@sss.pgh.pa.us 356 [ - + ]:CBC 64 : if (len != 20)
3362 tgl@sss.pgh.pa.us 357 :UBC 0 : return PXE_PGP_CORRUPT_DATA;
358 : :
359 : : /* mdc_read should not call px_md_update */
3362 tgl@sss.pgh.pa.us 360 :CBC 64 : ctx->in_mdc_pkt = 1;
361 : :
362 : : /* read data */
363 : 64 : res = pullf_read_max(src, len, &data, tmpbuf);
6853 bruce@momjian.us 364 [ - + ]: 64 : if (res < 0)
6853 bruce@momjian.us 365 :UBC 0 : return res;
6853 bruce@momjian.us 366 [ - + ]:CBC 64 : if (res == 0)
367 : : {
3362 tgl@sss.pgh.pa.us 368 :UBC 0 : px_debug("no mdc");
6853 bruce@momjian.us 369 : 0 : return PXE_PGP_CORRUPT_DATA;
370 : : }
371 : :
372 : : /* is the packet sane? */
6853 bruce@momjian.us 373 [ - + ]:CBC 64 : if (res != 20)
374 : : {
6853 bruce@momjian.us 375 :UBC 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 : : */
6853 bruce@momjian.us 382 :CBC 64 : px_md_finish(ctx->mdc_ctx, hash);
3362 tgl@sss.pgh.pa.us 383 : 64 : res = memcmp(hash, data, 20);
3650 bruce@momjian.us 384 : 64 : px_memset(hash, 0, 20);
385 : 64 : px_memset(tmpbuf, 0, sizeof(tmpbuf));
6853 386 [ - + ]: 64 : if (res != 0)
387 : : {
6853 bruce@momjian.us 388 :UBC 0 : px_debug("mdc_finish: mdc failed");
389 : 0 : return PXE_PGP_CORRUPT_DATA;
390 : : }
6853 bruce@momjian.us 391 :CBC 64 : ctx->mdc_checked = 1;
3362 tgl@sss.pgh.pa.us 392 : 64 : return 0;
393 : : }
394 : :
395 : : static int
5421 bruce@momjian.us 396 : 765 : mdc_read(void *priv, PullFilter *src, int len,
397 : : uint8 **data_p, uint8 *buf, int buflen)
398 : : {
399 : : int res;
6853 400 : 765 : PGP_Context *ctx = priv;
401 : :
402 : : /* skip this filter? */
3362 tgl@sss.pgh.pa.us 403 [ + + + + ]: 765 : if (ctx->use_mdcbuf_filter || ctx->in_mdc_pkt)
6853 bruce@momjian.us 404 : 135 : return pullf_read(src, len, data_p);
405 : :
406 : 630 : res = pullf_read(src, len, data_p);
407 [ - + ]: 630 : if (res < 0)
6853 bruce@momjian.us 408 :UBC 0 : return res;
6853 bruce@momjian.us 409 [ - + ]:CBC 630 : if (res == 0)
410 : : {
6853 bruce@momjian.us 411 :UBC 0 : px_debug("mdc_read: unexpected eof");
412 : 0 : return PXE_PGP_CORRUPT_DATA;
413 : : }
6853 bruce@momjian.us 414 :CBC 630 : px_md_update(ctx->mdc_ctx, *data_p, res);
415 : :
416 : 630 : 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
5421 446 : 3 : mdcbuf_init(void **priv_p, void *arg, PullFilter *src)
447 : : {
6853 448 : 3 : PGP_Context *ctx = arg;
449 : : struct MDCBufData *st;
450 : :
1297 michael@paquier.xyz 451 : 3 : st = palloc0(sizeof(*st));
6853 bruce@momjian.us 452 : 3 : st->buflen = sizeof(st->buf);
453 : 3 : st->ctx = ctx;
454 : 3 : *priv_p = st;
455 : :
456 : : /* take over the work of mdc_filter */
457 : 3 : ctx->use_mdcbuf_filter = 1;
458 : :
459 : 3 : return 0;
460 : : }
461 : :
462 : : static int
2489 tgl@sss.pgh.pa.us 463 : 3 : mdcbuf_finish(struct MDCBufData *st)
464 : : {
465 : : uint8 hash[20];
466 : : int res;
467 : :
6853 bruce@momjian.us 468 : 3 : st->eof = 1;
469 : :
470 [ + + - + ]: 3 : if (st->mdc_buf[0] != 0xD3 || st->mdc_buf[1] != 0x14)
471 : : {
472 : 2 : px_debug("mdcbuf_finish: bad MDC pkt hdr");
473 : 2 : return PXE_PGP_CORRUPT_DATA;
474 : : }
475 : 1 : px_md_update(st->ctx->mdc_ctx, st->mdc_buf, 2);
476 : 1 : px_md_finish(st->ctx->mdc_ctx, hash);
477 : 1 : res = memcmp(hash, st->mdc_buf + 2, 20);
3650 478 : 1 : px_memset(hash, 0, 20);
6853 479 [ - + ]: 1 : if (res)
480 : : {
6853 bruce@momjian.us 481 :UBC 0 : px_debug("mdcbuf_finish: MDC does not match");
482 : 0 : res = PXE_PGP_CORRUPT_DATA;
483 : : }
6853 bruce@momjian.us 484 :CBC 1 : return res;
485 : : }
486 : :
487 : : static void
2489 tgl@sss.pgh.pa.us 488 : 6 : mdcbuf_load_data(struct MDCBufData *st, uint8 *src, int len)
489 : : {
6756 bruce@momjian.us 490 : 6 : uint8 *dst = st->pos + st->avail;
491 : :
6853 492 : 6 : memcpy(dst, src, len);
493 : 6 : px_md_update(st->ctx->mdc_ctx, src, len);
494 : 6 : st->avail += len;
495 : 6 : }
496 : :
497 : : static void
2489 tgl@sss.pgh.pa.us 498 : 3 : mdcbuf_load_mdc(struct MDCBufData *st, uint8 *src, int len)
499 : : {
6853 bruce@momjian.us 500 : 3 : memmove(st->mdc_buf + st->mdc_avail, src, len);
501 : 3 : st->mdc_avail += len;
502 : 3 : }
503 : :
504 : : static int
2489 tgl@sss.pgh.pa.us 505 : 6 : mdcbuf_refill(struct MDCBufData *st, PullFilter *src)
506 : : {
507 : : uint8 *data;
508 : : int res;
509 : : int need;
510 : :
511 : : /* put avail data in start */
6853 bruce@momjian.us 512 [ + + + - ]: 6 : if (st->avail > 0 && st->pos != st->buf)
513 : 3 : memmove(st->buf, st->pos, st->avail);
514 : 6 : st->pos = st->buf;
515 : :
516 : : /* read new data */
517 : 6 : need = st->buflen + 22 - st->avail - st->mdc_avail;
518 : 6 : res = pullf_read(src, need, &data);
519 [ - + ]: 6 : if (res < 0)
6853 bruce@momjian.us 520 :UBC 0 : return res;
6853 bruce@momjian.us 521 [ + + ]:CBC 6 : if (res == 0)
522 : 3 : return mdcbuf_finish(st);
523 : :
524 : : /* add to buffer */
525 [ + - ]: 3 : if (res >= 22)
526 : : {
527 : 3 : mdcbuf_load_data(st, st->mdc_buf, st->mdc_avail);
528 : 3 : st->mdc_avail = 0;
529 : :
530 : 3 : mdcbuf_load_data(st, data, res - 22);
531 : 3 : mdcbuf_load_mdc(st, data + res - 22, 22);
532 : : }
533 : : else
534 : : {
6756 bruce@momjian.us 535 :UBC 0 : int canmove = st->mdc_avail + res - 22;
536 : :
6853 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 : : }
6853 bruce@momjian.us 545 :CBC 3 : return 0;
546 : : }
547 : :
548 : : static int
5421 549 : 10 : mdcbuf_read(void *priv, PullFilter *src, int len,
550 : : uint8 **data_p, uint8 *buf, int buflen)
551 : : {
6853 552 : 10 : struct MDCBufData *st = priv;
553 : : int res;
554 : :
555 [ + + + + ]: 10 : if (!st->eof && len > st->avail)
556 : : {
557 : 6 : res = mdcbuf_refill(st, src);
558 [ + + ]: 6 : if (res < 0)
559 : 2 : return res;
560 : : }
561 : :
562 [ + + ]: 8 : if (len > st->avail)
563 : 2 : len = st->avail;
564 : :
565 : 8 : *data_p = st->pos;
566 : 8 : st->pos += len;
567 : 8 : st->avail -= len;
568 : 8 : return len;
569 : : }
570 : :
571 : : static void
572 : 3 : mdcbuf_free(void *priv)
573 : : {
574 : 3 : struct MDCBufData *st = priv;
575 : :
576 : 3 : px_md_free(st->ctx->mdc_ctx);
577 : 3 : st->ctx->mdc_ctx = NULL;
3650 578 : 3 : px_memset(st, 0, sizeof(*st));
1297 michael@paquier.xyz 579 : 3 : pfree(st);
6853 bruce@momjian.us 580 : 3 : }
581 : :
582 : : static struct PullFilterOps mdcbuf_filter = {
583 : : mdcbuf_init, mdcbuf_read, mdcbuf_free
584 : : };
585 : :
586 : :
587 : : /*
588 : : * Decrypt separate session key
589 : : */
590 : : static int
5421 591 : 4 : decrypt_key(PGP_Context *ctx, const uint8 *src, int len)
592 : : {
593 : : int res;
594 : : uint8 algo;
595 : : PGP_CFB *cfb;
596 : :
6853 597 : 4 : res = pgp_cfb_create(&cfb, ctx->s2k_cipher_algo,
6756 598 : 4 : ctx->s2k.key, ctx->s2k.key_len, 0, NULL);
6853 599 [ - + ]: 4 : if (res < 0)
6853 bruce@momjian.us 600 :UBC 0 : return res;
601 : :
6853 bruce@momjian.us 602 :CBC 4 : pgp_cfb_decrypt(cfb, src, 1, &algo);
6756 603 : 4 : src++;
604 : 4 : len--;
605 : :
6853 606 : 4 : pgp_cfb_decrypt(cfb, src, len, ctx->sess_key);
607 : 4 : pgp_cfb_free(cfb);
608 : 4 : ctx->sess_key_len = len;
609 : 4 : ctx->cipher_algo = algo;
610 : :
6756 611 [ - + ]: 4 : if (pgp_get_cipher_key_size(algo) != len)
612 : : {
6853 bruce@momjian.us 613 :UBC 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 : : }
6853 bruce@momjian.us 617 :CBC 4 : return 0;
618 : : }
619 : :
620 : : /*
621 : : * Handle key packet
622 : : */
623 : : static int
5421 624 : 59 : 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 : :
6853 631 [ - + ]: 59 : GETBYTE(src, ver);
632 [ - + ]: 59 : GETBYTE(src, ctx->s2k_cipher_algo);
633 [ - + ]: 59 : if (ver != 4)
634 : : {
6853 bruce@momjian.us 635 :UBC 0 : px_debug("bad key pkt ver");
636 : 0 : return PXE_PGP_CORRUPT_DATA;
637 : : }
638 : :
639 : : /*
640 : : * read S2K info
641 : : */
6853 bruce@momjian.us 642 :CBC 59 : res = pgp_s2k_read(src, &ctx->s2k);
643 [ - + ]: 59 : if (res < 0)
6853 bruce@momjian.us 644 :UBC 0 : return res;
6853 bruce@momjian.us 645 :CBC 59 : ctx->s2k_mode = ctx->s2k.mode;
2958 alvherre@alvh.no-ip. 646 : 59 : ctx->s2k_count = s2k_decode_count(ctx->s2k.iter);
6853 bruce@momjian.us 647 : 59 : ctx->s2k_digest_algo = ctx->s2k.digest_algo;
648 : :
649 : : /*
650 : : * generate key from password
651 : : */
652 : 59 : res = pgp_s2k_process(&ctx->s2k, ctx->s2k_cipher_algo,
653 : : ctx->sym_key, ctx->sym_key_len);
654 [ - + ]: 59 : if (res < 0)
6853 bruce@momjian.us 655 :UBC 0 : return res;
656 : :
657 : : /*
658 : : * do we have separate session key?
659 : : */
6853 bruce@momjian.us 660 :CBC 59 : res = pullf_read_max(src, PGP_MAX_KEY + 2, &p, tmpbuf);
661 [ - + ]: 59 : if (res < 0)
6853 bruce@momjian.us 662 :UBC 0 : return res;
663 : :
6853 bruce@momjian.us 664 [ + + ]:CBC 59 : if (res == 0)
665 : : {
666 : : /*
667 : : * no, s2k key is session key
668 : : */
669 : 55 : memcpy(ctx->sess_key, ctx->s2k.key, ctx->s2k.key_len);
670 : 55 : ctx->sess_key_len = ctx->s2k.key_len;
671 : 55 : ctx->cipher_algo = ctx->s2k_cipher_algo;
672 : 55 : res = 0;
673 : 55 : ctx->use_sess_key = 0;
674 : : }
675 : : else
676 : : {
677 : : /*
678 : : * yes, decrypt it
679 : : */
680 [ + - - + ]: 4 : if (res < 17 || res > PGP_MAX_KEY + 1)
681 : : {
6853 bruce@momjian.us 682 :UBC 0 : px_debug("expect key, but bad data");
683 : 0 : return PXE_PGP_CORRUPT_DATA;
684 : : }
6853 bruce@momjian.us 685 :CBC 4 : ctx->use_sess_key = 1;
686 : 4 : res = decrypt_key(ctx, p, res);
687 : : }
688 : :
3650 689 : 59 : px_memset(tmpbuf, 0, sizeof(tmpbuf));
6853 690 : 59 : return res;
691 : : }
692 : :
693 : : static int
5421 694 : 2 : copy_crlf(MBuf *dst, uint8 *data, int len, int *got_cr)
695 : : {
6756 696 : 2 : uint8 *data_end = data + len;
697 : : uint8 tmpbuf[1024];
698 : 2 : uint8 *tmp_end = tmpbuf + sizeof(tmpbuf);
699 : : uint8 *p;
700 : : int res;
701 : :
6853 702 : 2 : p = tmpbuf;
6756 703 [ - + ]: 2 : if (*got_cr)
704 : : {
6853 bruce@momjian.us 705 [ # # ]:UBC 0 : if (*data != '\n')
706 : 0 : *p++ = '\r';
707 : 0 : *got_cr = 0;
708 : : }
6756 bruce@momjian.us 709 [ + - ]:CBC 47 : while (data < data_end)
710 : : {
6853 711 [ + + ]: 47 : if (*data == '\r')
712 : : {
713 [ + + ]: 14 : if (data + 1 < data_end)
714 : : {
715 [ + + ]: 12 : if (*(data + 1) == '\n')
716 : 7 : data++;
717 : : }
718 : : else
719 : : {
720 : 2 : *got_cr = 1;
721 : 2 : break;
722 : : }
723 : : }
724 : 45 : *p++ = *data++;
725 [ - + ]: 45 : if (p >= tmp_end)
726 : : {
6853 bruce@momjian.us 727 :UBC 0 : res = mbuf_append(dst, tmpbuf, p - tmpbuf);
728 [ # # ]: 0 : if (res < 0)
729 : 0 : return res;
730 : 0 : p = tmpbuf;
731 : : }
732 : : }
6853 bruce@momjian.us 733 [ + - ]:CBC 2 : if (p - tmpbuf > 0)
734 : : {
735 : 2 : res = mbuf_append(dst, tmpbuf, p - tmpbuf);
736 [ - + ]: 2 : if (res < 0)
6853 bruce@momjian.us 737 :UBC 0 : return res;
738 : : }
3650 bruce@momjian.us 739 :CBC 2 : px_memset(tmpbuf, 0, sizeof(tmpbuf));
6853 740 : 2 : return 0;
741 : : }
742 : :
743 : : static int
5421 744 : 67 : 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];
6853 751 : 67 : int got_cr = 0;
752 : :
753 [ - + ]: 67 : GETBYTE(pkt, type);
754 [ - + ]: 67 : GETBYTE(pkt, name_len);
755 : :
756 : : /* skip name */
757 [ + + ]: 90 : while (name_len > 0)
758 : : {
759 : 23 : res = pullf_read(pkt, name_len, &buf);
760 [ - + ]: 23 : if (res < 0)
6853 bruce@momjian.us 761 :UBC 0 : return res;
6853 bruce@momjian.us 762 [ - + ]:CBC 23 : if (res == 0)
6853 bruce@momjian.us 763 :UBC 0 : break;
6853 bruce@momjian.us 764 :CBC 23 : name_len -= res;
765 : : }
766 [ - + ]: 67 : if (name_len > 0)
767 : : {
6853 bruce@momjian.us 768 :UBC 0 : px_debug("parse_literal_data: unexpected eof");
769 : 0 : return PXE_PGP_CORRUPT_DATA;
770 : : }
771 : :
772 : : /* skip date */
6853 bruce@momjian.us 773 :CBC 67 : res = pullf_read_max(pkt, 4, &buf, tmpbuf);
774 [ - + ]: 67 : if (res != 4)
775 : : {
6853 bruce@momjian.us 776 :UBC 0 : px_debug("parse_literal_data: unexpected eof");
777 : 0 : return PXE_PGP_CORRUPT_DATA;
778 : : }
3650 bruce@momjian.us 779 :CBC 67 : 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 : : */
6853 785 [ + + ]: 67 : if (ctx->text_mode)
786 [ + + + - ]: 63 : if (type != 't' && type != 'u')
787 : : {
788 : 4 : px_debug("parse_literal_data: data type=%c", type);
3254 noah@leadboat.com 789 : 4 : ctx->unexpected_binary = true;
790 : : }
791 : :
6853 bruce@momjian.us 792 : 67 : ctx->unicode_mode = (type == 'u') ? 1 : 0;
793 : :
794 : : /* read data */
795 : : while (1)
796 : : {
6756 797 : 155 : res = pullf_read(pkt, 32 * 1024, &buf);
6853 798 [ + + ]: 155 : if (res <= 0)
799 : 67 : break;
800 : :
801 [ + + + + ]: 88 : if (ctx->text_mode && ctx->convert_crlf)
802 : 2 : res = copy_crlf(dst, buf, res, &got_cr);
803 : : else
804 : 86 : res = mbuf_append(dst, buf, res);
805 [ - + ]: 88 : if (res < 0)
6853 bruce@momjian.us 806 :UBC 0 : break;
807 : : }
6853 bruce@momjian.us 808 [ + + + + ]:CBC 67 : if (res >= 0 && got_cr)
6777 tgl@sss.pgh.pa.us 809 : 2 : res = mbuf_append(dst, (const uint8 *) "\r", 1);
6853 bruce@momjian.us 810 : 67 : 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
5421 818 : 6 : parse_compressed_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
819 : : {
820 : : int res;
821 : : uint8 type;
822 : : PullFilter *pf_decompr;
823 : : uint8 *discard_buf;
824 : :
6853 825 [ - + ]: 6 : GETBYTE(pkt, type);
826 : :
827 : 6 : ctx->compress_algo = type;
828 [ - + + - ]: 6 : switch (type)
829 : : {
6853 bruce@momjian.us 830 :UBC 0 : case PGP_COMPR_NONE:
831 : 0 : res = process_data_packets(ctx, dst, pkt, NO_COMPR, NO_MDC);
832 : 0 : break;
833 : :
6853 bruce@momjian.us 834 :CBC 4 : case PGP_COMPR_ZIP:
835 : : case PGP_COMPR_ZLIB:
836 : 4 : res = pgp_decompress_filter(&pf_decompr, ctx, pkt);
837 [ + - ]: 4 : if (res >= 0)
838 : : {
839 : 4 : res = process_data_packets(ctx, dst, pf_decompr,
840 : : NO_COMPR, NO_MDC);
841 : 4 : pullf_free(pf_decompr);
842 : : }
843 : 4 : break;
844 : :
845 : 2 : case PGP_COMPR_BZIP2:
846 : 2 : px_debug("parse_compressed_data: bzip2 unsupported");
847 : : /* report error in pgp_decrypt() */
3254 noah@leadboat.com 848 : 2 : ctx->unsupported_compr = 1;
849 : :
850 : : /*
851 : : * Discard the compressed data, allowing it to first affect any
852 : : * MDC digest computation.
853 : : */
854 : : while (1)
855 : : {
856 : 3 : res = pullf_read(pkt, 32 * 1024, &discard_buf);
857 [ + + ]: 3 : if (res <= 0)
858 : 2 : break;
859 : : }
860 : :
6853 bruce@momjian.us 861 : 2 : break;
862 : :
6853 bruce@momjian.us 863 :UBC 0 : default:
864 : 0 : px_debug("parse_compressed_data: unknown compr type");
865 : 0 : res = PXE_PGP_CORRUPT_DATA;
866 : : }
867 : :
6853 bruce@momjian.us 868 :CBC 6 : return res;
869 : : }
870 : :
871 : : static int
5421 872 : 76 : 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;
6853 878 : 76 : int got_data = 0;
879 : 76 : int got_mdc = 0;
880 : 76 : PullFilter *pkt = NULL;
881 : :
882 : : while (1)
883 : : {
884 : 211 : res = pgp_parse_pkt_hdr(src, &tag, &len, ALLOW_CTX_SIZE);
885 [ + + ]: 211 : if (res <= 0)
886 : 73 : break;
887 : :
888 : :
889 : : /* mdc packet should be last */
890 [ - + ]: 138 : if (got_mdc)
891 : : {
6853 bruce@momjian.us 892 :UBC 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 : : */
6853 bruce@momjian.us 901 [ + + + + ]:CBC 138 : if (need_mdc && res == PKT_CONTEXT)
902 : 3 : res = pullf_create(&pkt, &mdcbuf_filter, ctx, src);
903 : : else
904 : 135 : res = pgp_create_pkt_reader(&pkt, src, len, res, ctx);
905 [ - + ]: 138 : if (res < 0)
6853 bruce@momjian.us 906 :UBC 0 : break;
907 : :
6853 bruce@momjian.us 908 [ + + + + ]:CBC 138 : switch (tag)
909 : : {
910 : 67 : case PGP_PKT_LITERAL_DATA:
911 : 67 : got_data = 1;
912 : 67 : res = parse_literal_data(ctx, dst, pkt);
913 : 67 : break;
914 : 6 : case PGP_PKT_COMPRESSED_DATA:
915 [ - + ]: 6 : if (allow_compr == 0)
916 : : {
6853 bruce@momjian.us 917 :UBC 0 : px_debug("process_data_packets: unexpected compression");
918 : 0 : res = PXE_PGP_CORRUPT_DATA;
919 : : }
6853 bruce@momjian.us 920 [ - + ]:CBC 6 : else if (got_data)
921 : : {
922 : : /*
923 : : * compr data must be alone
924 : : */
6853 bruce@momjian.us 925 :UBC 0 : px_debug("process_data_packets: only one cmpr pkt allowed");
926 : 0 : res = PXE_PGP_CORRUPT_DATA;
927 : : }
928 : : else
929 : : {
6853 bruce@momjian.us 930 :CBC 6 : got_data = 1;
931 : 6 : res = parse_compressed_data(ctx, dst, pkt);
932 : : }
933 : 6 : break;
934 : 64 : case PGP_PKT_MDC:
935 [ - + ]: 64 : if (need_mdc == NO_MDC)
936 : : {
6853 bruce@momjian.us 937 :UBC 0 : px_debug("process_data_packets: unexpected MDC");
938 : 0 : res = PXE_PGP_CORRUPT_DATA;
939 : 0 : break;
940 : : }
941 : :
3362 tgl@sss.pgh.pa.us 942 :CBC 64 : res = mdc_finish(ctx, pkt, len);
943 [ + - ]: 64 : if (res >= 0)
6853 bruce@momjian.us 944 : 64 : got_mdc = 1;
945 : 64 : break;
946 : 1 : default:
947 : 1 : px_debug("process_data_packets: unexpected pkt tag=%d", tag);
948 : 1 : res = PXE_PGP_CORRUPT_DATA;
949 : : }
950 : :
951 : 138 : pullf_free(pkt);
952 : 138 : pkt = NULL;
953 : :
954 [ + + ]: 138 : if (res < 0)
955 : 3 : break;
956 : : }
957 : :
958 [ - + ]: 76 : if (pkt)
6853 bruce@momjian.us 959 :UBC 0 : pullf_free(pkt);
960 : :
6853 bruce@momjian.us 961 [ + + ]:CBC 76 : if (res < 0)
962 : 5 : return res;
963 : :
964 [ - + ]: 71 : if (!got_data)
965 : : {
6853 bruce@momjian.us 966 :UBC 0 : px_debug("process_data_packets: no data");
967 : 0 : res = PXE_PGP_CORRUPT_DATA;
968 : : }
6853 bruce@momjian.us 969 [ + + + + :CBC 71 : if (need_mdc && !got_mdc && !ctx->use_mdcbuf_filter)
- + ]
970 : : {
6853 bruce@momjian.us 971 :UBC 0 : px_debug("process_data_packets: got no mdc");
972 : 0 : res = PXE_PGP_CORRUPT_DATA;
973 : : }
6853 bruce@momjian.us 974 :CBC 71 : return res;
975 : : }
976 : :
977 : : static int
5421 978 : 2 : parse_symenc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
979 : : {
980 : : int res;
6756 981 : 2 : PGP_CFB *cfb = NULL;
6853 982 : 2 : PullFilter *pf_decrypt = NULL;
983 : 2 : PullFilter *pf_prefix = NULL;
984 : :
985 : 2 : res = pgp_cfb_create(&cfb, ctx->cipher_algo,
6756 986 : 2 : ctx->sess_key, ctx->sess_key_len, 1, NULL);
6853 987 [ - + ]: 2 : if (res < 0)
6853 bruce@momjian.us 988 :UBC 0 : goto out;
989 : :
6853 bruce@momjian.us 990 :CBC 2 : res = pullf_create(&pf_decrypt, &pgp_decrypt_filter, cfb, pkt);
991 [ - + ]: 2 : if (res < 0)
6853 bruce@momjian.us 992 :UBC 0 : goto out;
993 : :
6853 bruce@momjian.us 994 :CBC 2 : res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_decrypt);
995 [ - + ]: 2 : if (res < 0)
6853 bruce@momjian.us 996 :UBC 0 : goto out;
997 : :
6853 bruce@momjian.us 998 :CBC 2 : res = process_data_packets(ctx, dst, pf_prefix, ALLOW_COMPR, NO_MDC);
999 : :
1000 : 2 : out:
1001 [ + - ]: 2 : if (pf_prefix)
1002 : 2 : pullf_free(pf_prefix);
1003 [ + - ]: 2 : if (pf_decrypt)
1004 : 2 : pullf_free(pf_decrypt);
1005 [ + - ]: 2 : if (cfb)
1006 : 2 : pgp_cfb_free(cfb);
1007 : :
1008 : 2 : return res;
1009 : : }
1010 : :
1011 : : static int
5421 1012 : 70 : parse_symenc_mdc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
1013 : : {
1014 : : int res;
6756 1015 : 70 : PGP_CFB *cfb = NULL;
6853 1016 : 70 : PullFilter *pf_decrypt = NULL;
1017 : 70 : PullFilter *pf_prefix = NULL;
1018 : 70 : PullFilter *pf_mdc = NULL;
1019 : : uint8 ver;
1020 : :
1021 [ - + ]: 70 : GETBYTE(pkt, ver);
1022 [ - + ]: 70 : if (ver != 1)
1023 : : {
6853 bruce@momjian.us 1024 :UBC 0 : px_debug("parse_symenc_mdc_data: pkt ver != 1");
1025 : 0 : return PXE_PGP_CORRUPT_DATA;
1026 : : }
1027 : :
6853 bruce@momjian.us 1028 :CBC 70 : res = pgp_cfb_create(&cfb, ctx->cipher_algo,
6756 1029 : 70 : ctx->sess_key, ctx->sess_key_len, 0, NULL);
6853 1030 [ - + ]: 70 : if (res < 0)
6853 bruce@momjian.us 1031 :UBC 0 : goto out;
1032 : :
6853 bruce@momjian.us 1033 :CBC 70 : res = pullf_create(&pf_decrypt, &pgp_decrypt_filter, cfb, pkt);
1034 [ - + ]: 70 : if (res < 0)
6853 bruce@momjian.us 1035 :UBC 0 : goto out;
1036 : :
6853 bruce@momjian.us 1037 :CBC 70 : res = pullf_create(&pf_mdc, &mdc_filter, ctx, pf_decrypt);
1038 [ - + ]: 70 : if (res < 0)
6853 bruce@momjian.us 1039 :UBC 0 : goto out;
1040 : :
6853 bruce@momjian.us 1041 :CBC 70 : res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_mdc);
1042 [ - + ]: 70 : if (res < 0)
6853 bruce@momjian.us 1043 :UBC 0 : goto out;
1044 : :
6853 bruce@momjian.us 1045 :CBC 70 : res = process_data_packets(ctx, dst, pf_prefix, ALLOW_COMPR, NEED_MDC);
1046 : :
1047 : 70 : out:
1048 [ + - ]: 70 : if (pf_prefix)
1049 : 70 : pullf_free(pf_prefix);
1050 [ + - ]: 70 : if (pf_mdc)
1051 : 70 : pullf_free(pf_mdc);
1052 [ + - ]: 70 : if (pf_decrypt)
1053 : 70 : pullf_free(pf_decrypt);
1054 [ + - ]: 70 : if (cfb)
1055 : 70 : pgp_cfb_free(cfb);
1056 : :
1057 : 70 : return res;
1058 : : }
1059 : :
1060 : : /*
1061 : : * skip over packet contents
1062 : : */
1063 : : int
5421 1064 : 159 : pgp_skip_packet(PullFilter *pkt)
1065 : : {
6756 1066 : 159 : int res = 1;
1067 : : uint8 *tmp;
1068 : :
1069 [ + + ]: 472 : while (res > 0)
1070 : 313 : res = pullf_read(pkt, 32 * 1024, &tmp);
3451 noah@leadboat.com 1071 : 159 : return res;
1072 : : }
1073 : :
1074 : : /*
1075 : : * expect to be at packet end, any data is error
1076 : : */
1077 : : int
5421 bruce@momjian.us 1078 : 27 : pgp_expect_packet_end(PullFilter *pkt)
1079 : : {
1080 : : int res;
1081 : : uint8 *tmp;
1082 : :
3451 noah@leadboat.com 1083 : 27 : res = pullf_read(pkt, 32 * 1024, &tmp);
1084 [ - + ]: 27 : if (res > 0)
1085 : : {
3451 noah@leadboat.com 1086 :UBC 0 : px_debug("pgp_expect_packet_end: got data");
1087 : 0 : return PXE_PGP_CORRUPT_DATA;
1088 : : }
3451 noah@leadboat.com 1089 :CBC 27 : return res;
1090 : : }
1091 : :
1092 : : int
5421 bruce@momjian.us 1093 : 73 : pgp_decrypt(PGP_Context *ctx, MBuf *msrc, MBuf *mdst)
1094 : : {
1095 : : int res;
6853 1096 : 73 : PullFilter *src = NULL;
1097 : 73 : PullFilter *pkt = NULL;
1098 : : uint8 tag;
1099 : : int len;
6756 1100 : 73 : int got_key = 0;
1101 : 73 : int got_data = 0;
1102 : :
6853 1103 : 73 : res = pullf_create_mbuf_reader(&src, msrc);
1104 : :
6756 1105 [ + + ]: 218 : while (res >= 0)
1106 : : {
6853 1107 : 212 : res = pgp_parse_pkt_hdr(src, &tag, &len, NO_CTX_SIZE);
1108 [ + + ]: 212 : if (res <= 0)
1109 : 67 : break;
1110 : :
1111 : 145 : res = pgp_create_pkt_reader(&pkt, src, len, res, ctx);
1112 [ - + ]: 145 : if (res < 0)
6853 bruce@momjian.us 1113 :UBC 0 : break;
1114 : :
6853 bruce@momjian.us 1115 :CBC 145 : res = PXE_PGP_CORRUPT_DATA;
6756 1116 [ - + + + : 145 : switch (tag)
+ - ]
1117 : : {
6853 bruce@momjian.us 1118 :UBC 0 : case PGP_PKT_MARKER:
1119 : 0 : res = pgp_skip_packet(pkt);
1120 : 0 : break;
6853 bruce@momjian.us 1121 :CBC 14 : case PGP_PKT_PUBENCRYPTED_SESSKEY:
1122 : : /* fixme: skip those */
1123 : 14 : res = pgp_parse_pubenc_sesskey(ctx, pkt);
1124 : 14 : got_key = 1;
1125 : 14 : break;
1126 : 59 : case PGP_PKT_SYMENCRYPTED_SESSKEY:
1127 [ - + ]: 59 : 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 : : */
6853 bruce@momjian.us 1134 :UBC 0 : px_debug("pgp_decrypt: using first of several keys");
1135 : : else
1136 : : {
6853 bruce@momjian.us 1137 :CBC 59 : got_key = 1;
1138 : 59 : res = parse_symenc_sesskey(ctx, pkt);
1139 : : }
1140 : 59 : break;
1141 : 2 : case PGP_PKT_SYMENCRYPTED_DATA:
1142 [ - + ]: 2 : if (!got_key)
6853 bruce@momjian.us 1143 :UBC 0 : px_debug("pgp_decrypt: have data but no key");
6853 bruce@momjian.us 1144 [ - + ]:CBC 2 : else if (got_data)
6853 bruce@momjian.us 1145 :UBC 0 : px_debug("pgp_decrypt: got second data packet");
1146 : : else
1147 : : {
6853 bruce@momjian.us 1148 :CBC 2 : got_data = 1;
1149 : 2 : ctx->disable_mdc = 1;
1150 : 2 : res = parse_symenc_data(ctx, pkt, mdst);
1151 : : }
1152 : 2 : break;
1153 : 70 : case PGP_PKT_SYMENCRYPTED_DATA_MDC:
1154 [ - + ]: 70 : if (!got_key)
6853 bruce@momjian.us 1155 :UBC 0 : px_debug("pgp_decrypt: have data but no key");
6853 bruce@momjian.us 1156 [ - + ]:CBC 70 : else if (got_data)
6853 bruce@momjian.us 1157 :UBC 0 : px_debug("pgp_decrypt: several data pkts not supported");
1158 : : else
1159 : : {
6853 bruce@momjian.us 1160 :CBC 70 : got_data = 1;
1161 : 70 : ctx->disable_mdc = 0;
1162 : 70 : res = parse_symenc_mdc_data(ctx, pkt, mdst);
1163 : : }
1164 : 70 : break;
6853 bruce@momjian.us 1165 :UBC 0 : default:
1166 : 0 : px_debug("pgp_decrypt: unknown tag: 0x%02x", tag);
1167 : : }
6853 bruce@momjian.us 1168 :CBC 145 : pullf_free(pkt);
1169 : 145 : pkt = NULL;
1170 : : }
1171 : :
1172 [ - + ]: 73 : if (pkt)
6853 bruce@momjian.us 1173 :UBC 0 : pullf_free(pkt);
1174 : :
6853 bruce@momjian.us 1175 [ + - ]:CBC 73 : if (src)
1176 : 73 : pullf_free(src);
1177 : :
1178 [ + + ]: 73 : if (res < 0)
1179 : 6 : 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 [ + - - + ]: 67 : if (!got_data || ctx->corrupt_prefix)
3254 noah@leadboat.com 1187 :UBC 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 : : */
3254 noah@leadboat.com 1207 [ + + ]:CBC 67 : if (ctx->unsupported_compr)
1208 : 1 : return PXE_PGP_UNSUPPORTED_COMPR;
1209 [ + + ]: 66 : if (ctx->unexpected_binary)
1210 : 3 : return PXE_PGP_NOT_TEXT;
1211 : :
6853 bruce@momjian.us 1212 : 63 : return res;
1213 : : }
|