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