d00315480ff7282babe130bc1c52c7c5e79a3300
[apps/madmutt.git] / lib-crypt / pgppacket.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) 2001 Thomas Roessler <roessler@does-not-exist.org>
4  *
5  * This file is part of mutt-ng, see http://www.muttng.org/.
6  * It's licensed under the GNU General Public License,
7  * please see the file GPL in the top level source directory.
8  */
9
10 #include <lib-lib/lib-lib.h>
11 #include <lib-hash/hash.h>
12
13 #include "lib.h"
14 #include "pgplib.h"
15 #include "pgppacket.h"
16
17 #define CHUNKSIZE 1024
18
19 static unsigned char *pbuf = NULL;
20 static size_t plen = 0;
21
22 static int read_material (size_t material, size_t * used, FILE * fp)
23 {
24   if (*used + material >= plen) {
25     unsigned char *p;
26     size_t nplen;
27
28     nplen = *used + material + CHUNKSIZE;
29
30     if (!(p = realloc (pbuf, nplen))) { /* __MEM_CHECKED__ */
31       perror ("realloc");
32       return -1;
33     }
34     plen = nplen;
35     pbuf = p;
36   }
37
38   if (fread (pbuf + *used, 1, material, fp) < material) {
39     perror ("fread");
40     return -1;
41   }
42
43   *used += material;
44   return 0;
45 }
46
47 unsigned char *pgp_read_packet (FILE * fp, size_t * len)
48 {
49   size_t used = 0;
50   off_t startpos;
51   unsigned char ctb;
52   unsigned char b;
53   size_t material;
54
55   startpos = ftello (fp);
56
57   if (!plen) {
58     pbuf = p_new(unsigned char, plen = CHUNKSIZE);
59   }
60
61   if (fread (&ctb, 1, 1, fp) < 1) {
62     if (!feof (fp))
63       perror ("fread");
64     goto bail;
65   }
66
67   if (!(ctb & 0x80)) {
68     goto bail;
69   }
70
71   if (ctb & 0x40) {             /* handle PGP 5.0 packets. */
72     int partial = 0;
73
74     pbuf[0] = ctb;
75     used++;
76
77     do {
78       if (fread (&b, 1, 1, fp) < 1) {
79         perror ("fread");
80         goto bail;
81       }
82
83       if (b < 192) {
84         material = b;
85         partial = 0;
86         /* material -= 1; */
87       }
88       else if (192 <= b && b <= 223) {
89         material = (b - 192) * 256;
90         if (fread (&b, 1, 1, fp) < 1) {
91           perror ("fread");
92           goto bail;
93         }
94         material += b + 192;
95         partial = 0;
96         /* material -= 2; */
97       }
98       else if (b < 255) {
99         material = 1 << (b & 0x1f);
100         partial = 1;
101         /* material -= 1; */
102       }
103       else
104         /* b == 255 */
105       {
106         unsigned char buf[4];
107
108         if (fread (buf, 4, 1, fp) < 1) {
109           perror ("fread");
110           goto bail;
111         }
112         /*assert( sizeof(material) >= 4 ); */
113         material = buf[0] << 24;
114         material |= buf[1] << 16;
115         material |= buf[2] << 8;
116         material |= buf[3];
117         partial = 0;
118         /* material -= 5; */
119       }
120
121       if (read_material (material, &used, fp) == -1)
122         goto bail;
123
124     }
125     while (partial);
126   }
127   else
128     /* Old-Style PGP */
129   {
130     int bytes = 0;
131
132     pbuf[0] = 0x80 | ((ctb >> 2) & 0x0f);
133     used++;
134
135     switch (ctb & 0x03) {
136     case 0:
137       {
138         if (fread (&b, 1, 1, fp) < 1) {
139           perror ("fread");
140           goto bail;
141         }
142
143         material = b;
144         break;
145       }
146
147     case 1:
148       bytes = 2;
149
150     case 2:
151       {
152         int i;
153
154         if (!bytes)
155           bytes = 4;
156
157         material = 0;
158
159         for (i = 0; i < bytes; i++) {
160           if (fread (&b, 1, 1, fp) < 1) {
161             perror ("fread");
162             goto bail;
163           }
164
165           material = (material << 8) + b;
166         }
167         break;
168       }
169
170     default:
171       goto bail;
172     }
173
174     if (read_material (material, &used, fp) == -1)
175       goto bail;
176   }
177
178   if (len)
179     *len = used;
180
181   return pbuf;
182
183 bail:
184
185   fseeko (fp, startpos, SEEK_SET);
186   return NULL;
187 }
188
189 void pgp_release_packet (void)
190 {
191   plen = 0;
192   p_delete(&pbuf);
193 }