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