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