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