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