]> the.earth.li Git - onak.git/blob - armor.c
Add ability to drop overly large packets
[onak.git] / armor.c
1 /**
2  * @file armor.c
3  * @brief Routines to (de)armor OpenPGP packet streams.
4  *
5  * Copyright 2002-2004, 2011 Jonathan McDowell <noodles@earth.li>
6  *
7  * This program is free software: you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; version 2 of the License.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * this program.  If not, see <https://www.gnu.org/licenses/>.
18  */
19
20 #include <stdlib.h>
21
22 #include "armor.h"
23 #include "keystructs.h"
24 #include "parsekey.h"
25 #include "version.h"
26
27 /**
28  * @brief Line length we'll use for armored output
29  */
30 #define ARMOR_WIDTH 64
31
32 /**
33  * @brief CRC24 initialisation value
34  */
35 #define CRC24_INIT 0xb704ceL
36 /**
37  * @brief CRC24 polynomial value
38  */
39 #define CRC24_POLY 0x1864cfbL
40
41 /**
42  *
43  */
44 static unsigned char encode64(unsigned char c) {
45         if (c <= 25) {
46                 c += 'A';
47         } else if (c >= 26 && c <= 51) {
48                 c += 'a' - 26;
49         } else if (c >= 52 && c <= 61) {
50                 c += '0' - 52;
51         } else if (c == 62) {
52                 c = '+';
53         } else if (c == 63) {
54                 c = '/';
55         } else {
56                 c = '?';
57         }
58
59         return c;
60 }
61
62 /**
63  *
64  */
65 static unsigned char decode64(unsigned char c) {
66         if (c >= 'A' && c <= 'Z') {
67                 c -= 'A';
68         } else if (c >= 'a' && c <= 'z') {
69                 c -= 'a' - 26;
70         } else if (c >= '0' && c <= '9') {
71                 c -= '0' - 52;
72         } else if (c == '+') {
73                 c = 62;
74         } else if (c == '/') {
75                 c = 63;
76         } else if (c == '=' || c == '-') {
77                 c = 64;
78         } else {
79                 c = 65;
80         }
81
82         return c;
83 }
84
85 /**
86  * @brief Holds the context of an ongoing ASCII armor operation
87  */
88 struct armor_context {
89         /** The last octet we got. */
90         unsigned char lastoctet;
91         /** The current octet we're expecting (0, 1 or 2). */
92         int curoctet;
93         /** The number of octets we've seen. */
94         int count;
95         /** A running CRC24 of the data we've seen. */
96         long crc24;
97         /** The function to output a character. */
98         int (*putchar_func)(void *ctx, size_t count, void *c);
99         /** Context for putchar_func. */
100         void *ctx;
101 };
102
103 static void armor_init(struct armor_context *ctx)
104 {
105         ctx->curoctet = 0;
106         ctx->lastoctet = 0;
107         ctx->count = 0;
108         ctx->crc24 = CRC24_INIT;
109 }
110
111 static void armor_finish(struct armor_context *state)
112 {
113         unsigned char c;
114
115         switch (state->curoctet++) {
116         case 0:
117                 break;
118         case 1:
119                 c = encode64((state->lastoctet & 3) << 4);
120                 state->putchar_func(state->ctx, 1, &c);
121                 state->putchar_func(state->ctx, 1, (unsigned char *) "=");
122                 state->putchar_func(state->ctx, 1, (unsigned char *) "=");
123                 state->count += 3;
124                 if ((state->count % ARMOR_WIDTH) == 0) {
125                         state->putchar_func(state->ctx, 1,
126                                  (unsigned char *) "\n");
127                 }
128                 break;
129         case 2:
130                 c = encode64((state->lastoctet & 0xF) << 2);
131                 state->putchar_func(state->ctx, 1, &c);
132                 state->putchar_func(state->ctx, 1, (unsigned char *) "=");
133                 state->count += 2;
134                 if ((state->count % ARMOR_WIDTH) == 0) {
135                         state->putchar_func(state->ctx, 1,
136                                  (unsigned char *) "\n");
137                 }
138                 break;
139         }
140
141         state->crc24 &= 0xffffffL;
142         if ((state->count % ARMOR_WIDTH) != 0) {
143                 state->putchar_func(state->ctx, 1, (unsigned char *) "\n");
144         }
145         state->putchar_func(state->ctx, 1, (unsigned char *) "=");
146         c = encode64(state->crc24 >> 18);
147         state->putchar_func(state->ctx, 1, &c);
148         c = encode64((state->crc24 >> 12) & 0x3F);
149         state->putchar_func(state->ctx, 1, &c);
150         c = encode64((state->crc24 >> 6) & 0x3F);
151         state->putchar_func(state->ctx, 1, &c);
152         c = encode64(state->crc24 & 0x3F);
153         state->putchar_func(state->ctx, 1, &c);
154         state->putchar_func(state->ctx, 1, (unsigned char *) "\n");
155
156 }
157
158
159 static int armor_putchar_int(void *ctx, unsigned char c)
160 {
161         struct armor_context *state;
162         unsigned char t;
163         int i;
164
165         state = (struct armor_context *) ctx;
166
167         switch (state->curoctet++) {
168         case 0:
169                 t = encode64(c >> 2);
170                 state->putchar_func(state->ctx, 1, &t);
171                 state->count++;
172                 break;
173         case 1:
174                 t = encode64(((state->lastoctet & 3) << 4) + (c >> 4));
175                 state->putchar_func(state->ctx, 1, &t);
176                 state->count++;
177                 break;
178         case 2:
179                 t = encode64(((state->lastoctet & 0xF) << 2) + (c >> 6));
180                 state->putchar_func(state->ctx, 1, &t);
181                 t = encode64(c & 0x3F);
182                 state->putchar_func(state->ctx, 1, &t);
183                 state->count += 2;
184                 break;
185         }
186         state->curoctet %= 3;
187         state->lastoctet = c;
188         
189         state->crc24 ^= c << 16;
190         for (i = 0; i < 8; i++) {
191                 state->crc24 <<= 1;
192                 if (state->crc24 & 0x1000000) {
193                         state->crc24 ^= CRC24_POLY;
194                 }
195         }
196
197         if ((state->count % ARMOR_WIDTH) == 0) {
198                 state->putchar_func(state->ctx, 1, (unsigned char *) "\n");
199         }
200
201         return 0;
202 }
203
204
205 static int armor_putchar(void *ctx, size_t count, void *c)
206 {
207         int i;
208
209
210         for (i = 0; i < count; i++) {
211                 armor_putchar_int(ctx, ((char *) c)[i]);
212         }
213         
214         return 0;
215 }
216
217 /**
218  * @brief Holds the context of an ongoing ASCII dearmor operation
219  */
220 struct dearmor_context {
221         /** The last octet we got. */
222         unsigned char lastoctet;
223         /** The current octet we're expecting (0, 1 or 2). */
224         int curoctet;
225         /** The number of octets we've seen. */
226         int count;
227         /** A running CRC24 of the data we've seen. */
228         long crc24;
229         /** The function to get the next character. */
230         int (*getchar_func)(void *ctx, size_t count, void *c);
231         /** Context for getchar_func. */
232         void *ctx;
233 };
234
235 static void dearmor_init(struct dearmor_context *ctx)
236 {
237         ctx->curoctet = 0;
238         ctx->lastoctet = 0;
239         ctx->count = 0;
240         ctx->crc24 = CRC24_INIT;
241 }
242
243 static void dearmor_finish(struct dearmor_context *state)
244 {
245         /*
246          * Check the checksum
247          */
248
249         state->crc24 &= 0xffffffL;
250         /*
251         state->putchar_func(state->ctx, '\n');
252         state->putchar_func(state->ctx, '=');
253         state->putchar_func(state->ctx, encode64(state->crc24 >> 18));
254         state->putchar_func(state->ctx, encode64((state->crc24 >> 12) & 0x3F));
255         state->putchar_func(state->ctx, encode64((state->crc24 >> 6) & 0x3F));
256         state->putchar_func(state->ctx, encode64(state->crc24 & 0x3F));
257         */
258 }
259
260
261 static int dearmor_getchar(void *ctx, unsigned char *c)
262 {
263         struct dearmor_context *state;
264         unsigned char tmpc;
265         int i;
266
267         state = (struct dearmor_context *) ctx;
268         *c = 0;
269         
270         tmpc = 65;
271         while (tmpc == 65) {
272                 state->getchar_func(state->ctx, 1, &tmpc);
273                 tmpc = decode64(tmpc);
274         }
275
276         if (tmpc != 64) {
277                 switch (state->curoctet++) {
278                 case 0:
279                         state->lastoctet = tmpc;
280                         tmpc = 65;
281                         while (tmpc == 65) {
282                                 state->getchar_func(state->ctx, 1, &tmpc);
283                                 tmpc = decode64(tmpc);
284                         }
285                         *c = (state->lastoctet << 2) + (tmpc >> 4);
286                         break;
287                 case 1:
288                         *c = ((state->lastoctet & 0xF) << 4) + (tmpc >> 2);
289                         break;
290                 case 2:
291                         *c = ((state->lastoctet & 3) << 6) + tmpc;
292                         break;
293                 }
294         
295                 state->curoctet %= 3;
296                 state->lastoctet = tmpc;
297                 state->count++;
298                 
299                 state->crc24 ^= *c << 16;
300                 for (i = 0; i < 8; i++) {
301                         state->crc24 <<= 1;
302                         if (state->crc24 & 0x1000000) {
303                                 state->crc24 ^= CRC24_POLY;
304                         }
305                 }
306         }
307
308         return (tmpc == 64);
309 }
310
311 static int dearmor_getchar_c(void *ctx, size_t count, void *c)
312 {
313         int i, rc = 0;
314
315         for (i = 0; i < count && rc == 0; i++) {
316                 rc = dearmor_getchar(ctx, &((unsigned char *) c)[i]);
317         }
318
319         return rc;
320 }
321
322 int armor_openpgp_stream(int (*putchar_func)(void *ctx, size_t count,
323                                                 void *c),
324                                 void *ctx,
325                                 struct openpgp_packet_list *packets)
326 {
327         struct armor_context armor_ctx;
328
329         /*
330          * Print armor header
331          */
332         putchar_func(ctx, sizeof("-----BEGIN PGP PUBLIC KEY BLOCK-----\n") - 1,
333                 (unsigned char *) "-----BEGIN PGP PUBLIC KEY BLOCK-----\n");
334         putchar_func(ctx, sizeof("Version: onak " ONAK_VERSION "\n\n") - 1,
335                 (unsigned char *) "Version: onak " ONAK_VERSION "\n\n");
336         
337         armor_init(&armor_ctx);
338         armor_ctx.putchar_func = putchar_func;
339         armor_ctx.ctx = ctx;
340         write_openpgp_stream(armor_putchar, &armor_ctx, packets);
341         armor_finish(&armor_ctx);
342
343         /*
344          * Print armor footer
345          */
346         putchar_func(ctx, sizeof("-----END PGP PUBLIC KEY BLOCK-----\n") - 1,
347                 (unsigned char *) "-----END PGP PUBLIC KEY BLOCK-----\n");
348
349         return 0;
350 }
351
352 int dearmor_openpgp_stream(int (*getchar_func)(void *ctx, size_t count,
353                                                 void *c),
354                                 void *ctx,
355                                 struct openpgp_packet_list **packets)
356 {
357         struct dearmor_context dearmor_ctx;
358         unsigned char curchar;
359         int state = 0;
360         int count = 0;
361
362         /*
363          * Look for armor header. We want "-----BEGIN.*\n", then some headers
364          * with :s in them, then a blank line, then the data.
365          */
366         state = 1;
367         while (state != 4 && !getchar_func(ctx, 1, &curchar)) {
368                 switch (state) {
369                         case 0:
370                                 if (curchar == '\n') {
371                                         count = 0;
372                                         state = 1;
373                                 }
374                                 break;
375                         case 1:
376                                 if (curchar == '-') {
377                                         count++;
378                                         if (count == 5) {
379                                                 state = 2;
380                                         }
381                                 } else if (curchar != '\n') {
382                                         state = 0;
383                                 }
384                                 break;
385                         case 2:
386                                 if (curchar == 'B') {
387                                         count = 0;
388                                         state = 3;
389                                 } else {
390                                         state = 0;
391                                 }
392                                 break;
393                         case 3:
394                                 if (curchar == '\n') {
395                                         count++;
396                                         if (count == 2) {
397                                                 state = 4;
398                                         }
399                                 } else if (curchar != '\r') {
400                                         count = 0;
401                                 }
402                                 break;
403                 }
404         }
405
406         if (state == 4) {
407                 dearmor_init(&dearmor_ctx);
408                 dearmor_ctx.getchar_func = getchar_func;
409                 dearmor_ctx.ctx = ctx;
410                 read_openpgp_stream(dearmor_getchar_c, &dearmor_ctx,
411                         packets, 0);
412                 dearmor_finish(&dearmor_ctx);
413                 /*
414                  * TODO: Look for armor footer
415                  */
416         }
417
418         return 0;
419 }