450f8aaabd00bb74486fc930b99754854b048d05
[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 #if HAVE_CONFIG_H
11 # include "config.h"
12 #endif
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
18 #include <time.h>
19
20 #include <lib-lib/mem.h>
21 #include <lib-hash/hash.h>
22
23 #include "lib.h"
24 #include "pgplib.h"
25 #include "pgppacket.h"
26
27 #define CHUNKSIZE 1024
28
29 static unsigned char *pbuf = NULL;
30 static size_t plen = 0;
31
32 static int read_material (size_t material, size_t * used, FILE * fp)
33 {
34   if (*used + material >= plen) {
35     unsigned char *p;
36     size_t nplen;
37
38     nplen = *used + material + CHUNKSIZE;
39
40     if (!(p = realloc (pbuf, nplen))) { /* __MEM_CHECKED__ */
41       perror ("realloc");
42       return -1;
43     }
44     plen = nplen;
45     pbuf = p;
46   }
47
48   if (fread (pbuf + *used, 1, material, fp) < material) {
49     perror ("fread");
50     return -1;
51   }
52
53   *used += material;
54   return 0;
55 }
56
57 unsigned char *pgp_read_packet (FILE * fp, size_t * len)
58 {
59   size_t used = 0;
60   off_t startpos;
61   unsigned char ctb;
62   unsigned char b;
63   size_t material;
64
65   startpos = ftello (fp);
66
67   if (!plen) {
68     pbuf = p_new(unsigned char, plen = CHUNKSIZE);
69   }
70
71   if (fread (&ctb, 1, 1, fp) < 1) {
72     if (!feof (fp))
73       perror ("fread");
74     goto bail;
75   }
76
77   if (!(ctb & 0x80)) {
78     goto bail;
79   }
80
81   if (ctb & 0x40) {             /* handle PGP 5.0 packets. */
82     int partial = 0;
83
84     pbuf[0] = ctb;
85     used++;
86
87     do {
88       if (fread (&b, 1, 1, fp) < 1) {
89         perror ("fread");
90         goto bail;
91       }
92
93       if (b < 192) {
94         material = b;
95         partial = 0;
96         /* material -= 1; */
97       }
98       else if (192 <= b && b <= 223) {
99         material = (b - 192) * 256;
100         if (fread (&b, 1, 1, fp) < 1) {
101           perror ("fread");
102           goto bail;
103         }
104         material += b + 192;
105         partial = 0;
106         /* material -= 2; */
107       }
108       else if (b < 255) {
109         material = 1 << (b & 0x1f);
110         partial = 1;
111         /* material -= 1; */
112       }
113       else
114         /* b == 255 */
115       {
116         unsigned char buf[4];
117
118         if (fread (buf, 4, 1, fp) < 1) {
119           perror ("fread");
120           goto bail;
121         }
122         /*assert( sizeof(material) >= 4 ); */
123         material = buf[0] << 24;
124         material |= buf[1] << 16;
125         material |= buf[2] << 8;
126         material |= buf[3];
127         partial = 0;
128         /* material -= 5; */
129       }
130
131       if (read_material (material, &used, fp) == -1)
132         goto bail;
133
134     }
135     while (partial);
136   }
137   else
138     /* Old-Style PGP */
139   {
140     int bytes = 0;
141
142     pbuf[0] = 0x80 | ((ctb >> 2) & 0x0f);
143     used++;
144
145     switch (ctb & 0x03) {
146     case 0:
147       {
148         if (fread (&b, 1, 1, fp) < 1) {
149           perror ("fread");
150           goto bail;
151         }
152
153         material = b;
154         break;
155       }
156
157     case 1:
158       bytes = 2;
159
160     case 2:
161       {
162         int i;
163
164         if (!bytes)
165           bytes = 4;
166
167         material = 0;
168
169         for (i = 0; i < bytes; i++) {
170           if (fread (&b, 1, 1, fp) < 1) {
171             perror ("fread");
172             goto bail;
173           }
174
175           material = (material << 8) + b;
176         }
177         break;
178       }
179
180     default:
181       goto bail;
182     }
183
184     if (read_material (material, &used, fp) == -1)
185       goto bail;
186   }
187
188   if (len)
189     *len = used;
190
191   return pbuf;
192
193 bail:
194
195   fseeko (fp, startpos, SEEK_SET);
196   return NULL;
197 }
198
199 void pgp_release_packet (void)
200 {
201   plen = 0;
202   p_delete(&pbuf);
203 }