Line data Source code
1 : /* armor.c - Armor flter
2 : * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
3 : * 2007 Free Software Foundation, Inc.
4 : *
5 : * This file is part of GnuPG.
6 : *
7 : * GnuPG is free software; you can redistribute it and/or modify
8 : * it under the terms of the GNU General Public License as published by
9 : * the Free Software Foundation; either version 3 of the License, or
10 : * (at your option) any later version.
11 : *
12 : * GnuPG is distributed in the hope that it will be useful,
13 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : * GNU General Public License for more details.
16 : *
17 : * You should have received a copy of the GNU General Public License
18 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include <config.h>
22 : #include <stdio.h>
23 : #include <stdlib.h>
24 : #include <string.h>
25 : #include <errno.h>
26 : #include <assert.h>
27 : #include <ctype.h>
28 :
29 : #include "gpg.h"
30 : #include "status.h"
31 : #include "iobuf.h"
32 : #include "util.h"
33 : #include "filter.h"
34 : #include "packet.h"
35 : #include "options.h"
36 : #include "main.h"
37 : #include "status.h"
38 : #include "i18n.h"
39 :
40 : #define MAX_LINELEN 20000
41 :
42 : #define CRCINIT 0xB704CE
43 : #define CRCPOLY 0X864CFB
44 : #define CRCUPDATE(a,c) do { \
45 : a = ((a) << 8) ^ crc_table[((a)&0xff >> 16) ^ (c)]; \
46 : a &= 0x00ffffff; \
47 : } while(0)
48 : static u32 crc_table[256];
49 : static byte bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
50 : "abcdefghijklmnopqrstuvwxyz"
51 : "0123456789+/";
52 : static byte asctobin[256]; /* runtime initialized */
53 : static int is_initialized;
54 :
55 :
56 : typedef enum {
57 : fhdrHASArmor = 0,
58 : fhdrNOArmor,
59 : fhdrINIT,
60 : fhdrINITCont,
61 : fhdrINITSkip,
62 : fhdrCHECKBegin,
63 : fhdrWAITHeader,
64 : fhdrWAITClearsig,
65 : fhdrSKIPHeader,
66 : fhdrCLEARSIG,
67 : fhdrREADClearsig,
68 : fhdrNullClearsig,
69 : fhdrEMPTYClearsig,
70 : fhdrCHECKClearsig,
71 : fhdrCHECKClearsig2,
72 : fhdrCHECKDashEscaped,
73 : fhdrCHECKDashEscaped2,
74 : fhdrCHECKDashEscaped3,
75 : fhdrREADClearsigNext,
76 : fhdrENDClearsig,
77 : fhdrENDClearsigHelp,
78 : fhdrTESTSpaces,
79 : fhdrCLEARSIGSimple,
80 : fhdrCLEARSIGSimpleNext,
81 : fhdrTEXT,
82 : fhdrTEXTSimple,
83 : fhdrERROR,
84 : fhdrERRORShow,
85 : fhdrEOF
86 : } fhdr_state_t;
87 :
88 :
89 : /* if we encounter this armor string with this index, go
90 : * into a mode which fakes packets and wait for the next armor */
91 : #define BEGIN_SIGNATURE 2
92 : #define BEGIN_SIGNED_MSG_IDX 3
93 : static char *head_strings[] = {
94 : "BEGIN PGP MESSAGE",
95 : "BEGIN PGP PUBLIC KEY BLOCK",
96 : "BEGIN PGP SIGNATURE",
97 : "BEGIN PGP SIGNED MESSAGE",
98 : "BEGIN PGP ARMORED FILE", /* gnupg extension */
99 : "BEGIN PGP PRIVATE KEY BLOCK",
100 : "BEGIN PGP SECRET KEY BLOCK", /* only used by pgp2 */
101 : NULL
102 : };
103 : static char *tail_strings[] = {
104 : "END PGP MESSAGE",
105 : "END PGP PUBLIC KEY BLOCK",
106 : "END PGP SIGNATURE",
107 : "END dummy",
108 : "END PGP ARMORED FILE",
109 : "END PGP PRIVATE KEY BLOCK",
110 : "END PGP SECRET KEY BLOCK",
111 : NULL
112 : };
113 :
114 :
115 : static int armor_filter ( void *opaque, int control,
116 : iobuf_t chain, byte *buf, size_t *ret_len);
117 :
118 :
119 :
120 :
121 : /* Create a new context for armor filters. */
122 : armor_filter_context_t *
123 263 : new_armor_context (void)
124 : {
125 : armor_filter_context_t *afx;
126 :
127 263 : afx = xcalloc (1, sizeof *afx);
128 263 : afx->refcount = 1;
129 :
130 263 : return afx;
131 : }
132 :
133 : /* Release an armor filter context. Passing NULL is explicitly
134 : allowed and a no-op. */
135 : void
136 2071 : release_armor_context (armor_filter_context_t *afx)
137 : {
138 2071 : if (!afx)
139 1629 : return;
140 442 : assert (afx->refcount);
141 442 : if ( --afx->refcount )
142 181 : return;
143 261 : xfree (afx);
144 : }
145 :
146 : /* Push the armor filter onto the iobuf stream IOBUF. */
147 : int
148 181 : push_armor_filter (armor_filter_context_t *afx, iobuf_t iobuf)
149 : {
150 : int rc;
151 :
152 181 : afx->refcount++;
153 181 : rc = iobuf_push_filter (iobuf, armor_filter, afx);
154 181 : if (rc)
155 0 : afx->refcount--;
156 181 : return rc;
157 : }
158 :
159 :
160 :
161 :
162 :
163 : static void
164 180 : initialize(void)
165 : {
166 : int i, j;
167 : u32 t;
168 : byte *s;
169 :
170 : /* init the crc lookup table */
171 180 : crc_table[0] = 0;
172 23220 : for(i=j=0; j < 128; j++ ) {
173 23040 : t = crc_table[j];
174 23040 : if( t & 0x00800000 ) {
175 11520 : t <<= 1;
176 11520 : crc_table[i++] = t ^ CRCPOLY;
177 11520 : crc_table[i++] = t;
178 : }
179 : else {
180 11520 : t <<= 1;
181 11520 : crc_table[i++] = t;
182 11520 : crc_table[i++] = t ^ CRCPOLY;
183 : }
184 : }
185 : /* build the helptable for radix64 to bin conversion */
186 46260 : for(i=0; i < 256; i++ )
187 46080 : asctobin[i] = 255; /* used to detect invalid characters */
188 11700 : for(s=bintoasc,i=0; *s; s++,i++ )
189 11520 : asctobin[*s] = i;
190 :
191 180 : is_initialized=1;
192 180 : }
193 :
194 : /****************
195 : * Check whether this is an armored file or not See also
196 : * parse-packet.c for details on this code For unknown historic
197 : * reasons we use a string here but only the first byte will be used.
198 : * Returns: True if it seems to be armored
199 : */
200 : static int
201 842 : is_armored( const byte *buf )
202 : {
203 : int ctb, pkttype;
204 :
205 842 : ctb = *buf;
206 842 : if( !(ctb & 0x80) )
207 343 : return 1; /* invalid packet: assume it is armored */
208 499 : pkttype = ctb & 0x40 ? (ctb & 0x3f) : ((ctb>>2)&0xf);
209 499 : switch( pkttype ) {
210 : case PKT_MARKER:
211 : case PKT_SYMKEY_ENC:
212 : case PKT_ONEPASS_SIG:
213 : case PKT_PUBLIC_KEY:
214 : case PKT_SECRET_KEY:
215 : case PKT_PUBKEY_ENC:
216 : case PKT_SIGNATURE:
217 : case PKT_COMMENT:
218 : case PKT_OLD_COMMENT:
219 : case PKT_PLAINTEXT:
220 : case PKT_COMPRESSED:
221 : case PKT_ENCRYPTED:
222 499 : return 0; /* seems to be a regular packet: not armored */
223 : }
224 :
225 0 : return 1;
226 : }
227 :
228 :
229 : /****************
230 : * Try to check whether the iobuf is armored
231 : * Returns true if this may be the case; the caller should use the
232 : * filter to do further processing.
233 : */
234 : int
235 588 : use_armor_filter( IOBUF a )
236 : {
237 : byte buf[1];
238 : int n;
239 :
240 : /* fixme: there might be a problem with iobuf_peek */
241 588 : n = iobuf_peek(a, buf, 1 );
242 588 : if( n == -1 )
243 0 : return 0; /* EOF, doesn't matter whether armored or not */
244 588 : if( !n )
245 0 : return 1; /* can't check it: try armored */
246 588 : return is_armored(buf);
247 : }
248 :
249 :
250 :
251 :
252 : static void
253 0 : invalid_armor(void)
254 : {
255 0 : write_status(STATUS_BADARMOR);
256 0 : g10_exit(1); /* stop here */
257 : }
258 :
259 :
260 : /****************
261 : * check whether the armor header is valid on a signed message.
262 : * this is for security reasons: the header lines are not included in the
263 : * hash and by using some creative formatting rules, Mallory could fake
264 : * any text at the beginning of a document; assuming it is read with
265 : * a simple viewer. We only allow the Hash Header.
266 : */
267 : static int
268 17 : parse_hash_header( const char *line )
269 : {
270 : const char *s, *s2;
271 17 : unsigned found = 0;
272 :
273 17 : if( strlen(line) < 6 || strlen(line) > 60 )
274 0 : return 0; /* too short or too long */
275 17 : if( memcmp( line, "Hash:", 5 ) )
276 1 : return 0; /* invalid header */
277 16 : s = line+5;
278 32 : for(s=line+5;;s=s2) {
279 32 : for(; *s && (*s==' ' || *s == '\t'); s++ )
280 : ;
281 32 : if( !*s )
282 16 : break;
283 16 : for(s2=s+1; *s2 && *s2!=' ' && *s2 != '\t' && *s2 != ','; s2++ )
284 : ;
285 16 : if( !strncmp( s, "RIPEMD160", s2-s ) )
286 0 : found |= 1;
287 16 : else if( !strncmp( s, "SHA1", s2-s ) )
288 16 : found |= 2;
289 0 : else if( !strncmp( s, "SHA224", s2-s ) )
290 0 : found |= 8;
291 0 : else if( !strncmp( s, "SHA256", s2-s ) )
292 0 : found |= 16;
293 0 : else if( !strncmp( s, "SHA384", s2-s ) )
294 0 : found |= 32;
295 0 : else if( !strncmp( s, "SHA512", s2-s ) )
296 0 : found |= 64;
297 : else
298 0 : return 0;
299 16 : for(; *s2 && (*s2==' ' || *s2 == '\t'); s2++ )
300 : ;
301 16 : if( *s2 && *s2 != ',' )
302 0 : return 0;
303 16 : if( *s2 )
304 0 : s2++;
305 16 : }
306 16 : return found;
307 : }
308 :
309 : /* Returns true if this is a valid armor tag as per RFC-2440bis-21. */
310 : static int
311 123 : is_armor_tag(const char *line)
312 : {
313 123 : if(strncmp(line,"Version",7)==0
314 17 : || strncmp(line,"Comment",7)==0
315 0 : || strncmp(line,"MessageID",9)==0
316 0 : || strncmp(line,"Hash",4)==0
317 0 : || strncmp(line,"Charset",7)==0)
318 123 : return 1;
319 :
320 0 : return 0;
321 : }
322 :
323 : /****************
324 : * Check whether this is a armor line.
325 : * returns: -1 if it is not a armor header or the index number of the
326 : * armor header.
327 : */
328 : static int
329 453 : is_armor_header( byte *line, unsigned len )
330 : {
331 : const char *s;
332 : byte *save_p, *p;
333 : int save_c;
334 : int i;
335 :
336 453 : if( len < 15 )
337 52 : return -1; /* too short */
338 401 : if( memcmp( line, "-----", 5 ) )
339 122 : return -1; /* no */
340 279 : p = strstr( line+5, "-----");
341 279 : if( !p )
342 2 : return -1;
343 277 : save_p = p;
344 277 : p += 5;
345 :
346 : /* Some Windows environments seem to add whitespace to the end of
347 : the line, so we strip it here. This becomes strict if
348 : --rfc2440 is set since 2440 reads "The header lines, therefore,
349 : MUST start at the beginning of a line, and MUST NOT have text
350 : following them on the same line." It is unclear whether "text"
351 : refers to all text or just non-whitespace text. 4880 clarified
352 : this was only non-whitespace text. */
353 :
354 277 : if(RFC2440)
355 : {
356 0 : if( *p == '\r' )
357 0 : p++;
358 0 : if( *p == '\n' )
359 0 : p++;
360 : }
361 : else
362 830 : while(*p==' ' || *p=='\r' || *p=='\n' || *p=='\t')
363 276 : p++;
364 :
365 277 : if( *p )
366 1 : return -1; /* garbage after dashes */
367 276 : save_c = *save_p; *save_p = 0;
368 276 : p = line+5;
369 1403 : for(i=0; (s=head_strings[i]); i++ )
370 1274 : if( !strcmp(s, p) )
371 147 : break;
372 276 : *save_p = save_c;
373 276 : if( !s )
374 129 : return -1; /* unknown armor line */
375 :
376 147 : if( opt.verbose > 1 )
377 0 : log_info(_("armor: %s\n"), head_strings[i]);
378 147 : return i;
379 : }
380 :
381 :
382 :
383 : /****************
384 : * Parse a header lines
385 : * Return 0: Empty line (end of header lines)
386 : * -1: invalid header line
387 : * >0: Good header line
388 : */
389 : static int
390 287 : parse_header_line( armor_filter_context_t *afx, byte *line, unsigned int len )
391 : {
392 : byte *p;
393 287 : int hashes=0;
394 : unsigned int len2;
395 :
396 287 : len2 = length_sans_trailing_ws ( line, len );
397 287 : if( !len2 ) {
398 147 : afx->buffer_pos = len2; /* (it is not the fine way to do it here) */
399 147 : return 0; /* WS only: same as empty line */
400 : }
401 :
402 : /*
403 : This is fussy. The spec says that a header line is delimited
404 : with a colon-space pair. This means that a line such as
405 : "Comment: " (with nothing else) is actually legal as an empty
406 : string comment. However, email and cut-and-paste being what it
407 : is, that trailing space may go away. Therefore, we accept empty
408 : headers delimited with only a colon. --rfc2440, as always,
409 : makes this strict and enforces the colon-space pair. -dms
410 : */
411 :
412 140 : p = strchr( line, ':');
413 140 : if( !p || (RFC2440 && p[1]!=' ')
414 140 : || (!RFC2440 && p[1]!=' ' && p[1]!='\n' && p[1]!='\r'))
415 : {
416 0 : log_error (_("invalid armor header: "));
417 0 : es_write_sanitized (log_get_stream (), line, len, NULL, NULL);
418 0 : log_printf ("\n");
419 0 : return -1;
420 : }
421 :
422 : /* Chop off the whitespace we detected before */
423 140 : len=len2;
424 140 : line[len2]='\0';
425 :
426 140 : if( opt.verbose ) {
427 0 : log_info(_("armor header: "));
428 0 : es_write_sanitized (log_get_stream (), line, len, NULL, NULL);
429 0 : log_printf ("\n");
430 : }
431 :
432 140 : if( afx->in_cleartext )
433 : {
434 17 : if( (hashes=parse_hash_header( line )) )
435 16 : afx->hashes |= hashes;
436 1 : else if( strlen(line) > 15 && !memcmp( line, "NotDashEscaped:", 15 ) )
437 1 : afx->not_dash_escaped = 1;
438 : else
439 : {
440 0 : log_error(_("invalid clearsig header\n"));
441 0 : return -1;
442 : }
443 : }
444 123 : else if(!is_armor_tag(line))
445 : {
446 : /* Section 6.2: "Unknown keys should be reported to the user,
447 : but OpenPGP should continue to process the message." Note
448 : that in a clearsigned message this applies to the signature
449 : part (i.e. "BEGIN PGP SIGNATURE") and not the signed data
450 : ("BEGIN PGP SIGNED MESSAGE"). The only key allowed in the
451 : signed data section is "Hash". */
452 :
453 0 : log_info(_("unknown armor header: "));
454 0 : es_write_sanitized (log_get_stream (), line, len, NULL, NULL);
455 0 : log_printf ("\n");
456 : }
457 :
458 140 : return 1;
459 : }
460 :
461 :
462 :
463 : /* figure out whether the data is armored or not */
464 : static int
465 261 : check_input( armor_filter_context_t *afx, IOBUF a )
466 : {
467 261 : int rc = 0;
468 : int i;
469 : byte *line;
470 : unsigned len;
471 : unsigned maxlen;
472 261 : int hdr_line = -1;
473 :
474 : /* read the first line to see whether this is armored data */
475 261 : maxlen = MAX_LINELEN;
476 261 : len = afx->buffer_len = iobuf_read_line( a, &afx->buffer,
477 : &afx->buffer_size, &maxlen );
478 261 : line = afx->buffer;
479 261 : if( !maxlen ) {
480 : /* line has been truncated: assume not armored */
481 0 : afx->inp_checked = 1;
482 0 : afx->inp_bypass = 1;
483 0 : return 0;
484 : }
485 :
486 261 : if( !len ) {
487 0 : return -1; /* eof */
488 : }
489 :
490 : /* (the line is always a C string but maybe longer) */
491 261 : if( *line == '\n' || ( len && (*line == '\r' && line[1]=='\n') ) )
492 : ;
493 254 : else if( !is_armored( line ) ) {
494 1 : afx->inp_checked = 1;
495 1 : afx->inp_bypass = 1;
496 1 : return 0;
497 : }
498 :
499 : /* find the armor header */
500 826 : while(len) {
501 437 : i = is_armor_header( line, len );
502 437 : if( i >= 0 && !(afx->only_keyblocks && i != 1 && i != 5 && i != 6 )) {
503 131 : hdr_line = i;
504 131 : if( hdr_line == BEGIN_SIGNED_MSG_IDX ) {
505 16 : if( afx->in_cleartext ) {
506 0 : log_error(_("nested clear text signatures\n"));
507 0 : rc = gpg_error (GPG_ERR_INV_ARMOR);
508 : }
509 16 : afx->in_cleartext = 1;
510 : }
511 131 : break;
512 : }
513 : /* read the next line (skip all truncated lines) */
514 : do {
515 306 : maxlen = MAX_LINELEN;
516 306 : afx->buffer_len = iobuf_read_line( a, &afx->buffer,
517 : &afx->buffer_size, &maxlen );
518 306 : line = afx->buffer;
519 306 : len = afx->buffer_len;
520 306 : } while( !maxlen );
521 : }
522 :
523 : /* Parse the header lines. */
524 650 : while(len) {
525 : /* Read the next line (skip all truncated lines). */
526 : do {
527 261 : maxlen = MAX_LINELEN;
528 261 : afx->buffer_len = iobuf_read_line( a, &afx->buffer,
529 : &afx->buffer_size, &maxlen );
530 261 : line = afx->buffer;
531 261 : len = afx->buffer_len;
532 261 : } while( !maxlen );
533 :
534 261 : i = parse_header_line( afx, line, len );
535 261 : if( i <= 0 ) {
536 131 : if (i && RFC2440)
537 0 : rc = GPG_ERR_INV_ARMOR;
538 131 : break;
539 : }
540 : }
541 :
542 :
543 260 : if( rc )
544 0 : invalid_armor();
545 260 : else if( afx->in_cleartext )
546 16 : afx->faked = 1;
547 : else {
548 244 : afx->inp_checked = 1;
549 244 : afx->crc = CRCINIT;
550 244 : afx->idx = 0;
551 244 : afx->radbuf[0] = 0;
552 : }
553 :
554 260 : return rc;
555 : }
556 :
557 : #define PARTIAL_CHUNK 512
558 : #define PARTIAL_POW 9
559 :
560 : /****************
561 : * Fake a literal data packet and wait for the next armor line
562 : * fixme: empty line handling and null length clear text signature are
563 : * not implemented/checked.
564 : */
565 : static int
566 42 : fake_packet( armor_filter_context_t *afx, IOBUF a,
567 : size_t *retn, byte *buf, size_t size )
568 : {
569 42 : int rc = 0;
570 42 : size_t len = 0;
571 42 : int lastline = 0;
572 : unsigned maxlen, n;
573 : byte *p;
574 : byte tempbuf[PARTIAL_CHUNK];
575 42 : size_t tempbuf_len=0;
576 :
577 6154 : while( !rc && size-len>=(PARTIAL_CHUNK+1)) {
578 : /* copy what we have in the line buffer */
579 6070 : if( afx->faked == 1 )
580 16 : afx->faked++; /* skip the first (empty) line */
581 : else
582 : {
583 : /* It's full, so write this partial chunk */
584 6054 : if(tempbuf_len==PARTIAL_CHUNK)
585 : {
586 395 : buf[len++]=0xE0+PARTIAL_POW;
587 395 : memcpy(&buf[len],tempbuf,PARTIAL_CHUNK);
588 395 : len+=PARTIAL_CHUNK;
589 395 : tempbuf_len=0;
590 395 : continue;
591 : }
592 :
593 215932 : while( tempbuf_len < PARTIAL_CHUNK
594 209878 : && afx->buffer_pos < afx->buffer_len )
595 204614 : tempbuf[tempbuf_len++] = afx->buffer[afx->buffer_pos++];
596 5659 : if( tempbuf_len==PARTIAL_CHUNK )
597 395 : continue;
598 : }
599 :
600 : /* read the next line */
601 5280 : maxlen = MAX_LINELEN;
602 5280 : afx->buffer_pos = 0;
603 5280 : afx->buffer_len = iobuf_read_line( a, &afx->buffer,
604 : &afx->buffer_size, &maxlen );
605 5280 : if( !afx->buffer_len ) {
606 0 : rc = -1; /* eof (should not happen) */
607 0 : continue;
608 : }
609 5280 : if( !maxlen )
610 0 : afx->truncated++;
611 :
612 5280 : p = afx->buffer;
613 5280 : n = afx->buffer_len;
614 :
615 : /* Armor header or dash-escaped line? */
616 5280 : if(p[0]=='-')
617 : {
618 : /* 2440bis-10: When reversing dash-escaping, an
619 : implementation MUST strip the string "- " if it occurs
620 : at the beginning of a line, and SHOULD warn on "-" and
621 : any character other than a space at the beginning of a
622 : line. */
623 :
624 29 : if(p[1]==' ' && !afx->not_dash_escaped)
625 : {
626 : /* It's a dash-escaped line, so skip over the
627 : escape. */
628 11 : afx->buffer_pos = 2;
629 : }
630 18 : else if(p[1]=='-' && p[2]=='-' && p[3]=='-' && p[4]=='-')
631 16 : {
632 : /* Five dashes in a row mean it's probably armor
633 : header. */
634 16 : int type = is_armor_header( p, n );
635 16 : if( afx->not_dash_escaped && type != BEGIN_SIGNATURE )
636 : ; /* this is okay */
637 : else
638 : {
639 16 : if( type != BEGIN_SIGNATURE )
640 : {
641 0 : log_info(_("unexpected armor: "));
642 0 : es_write_sanitized (log_get_stream (), p, n,
643 : NULL, NULL);
644 0 : log_printf ("\n");
645 : }
646 :
647 16 : lastline = 1;
648 16 : rc = -1;
649 : }
650 : }
651 2 : else if(!afx->not_dash_escaped)
652 : {
653 : /* Bad dash-escaping. */
654 0 : log_info (_("invalid dash escaped line: "));
655 0 : es_write_sanitized (log_get_stream (), p, n, NULL, NULL);
656 0 : log_printf ("\n");
657 : }
658 : }
659 :
660 : /* Now handle the end-of-line canonicalization */
661 5280 : if( !afx->not_dash_escaped )
662 : {
663 5268 : int crlf = n > 1 && p[n-2] == '\r' && p[n-1]=='\n';
664 :
665 5268 : afx->buffer_len=
666 5268 : trim_trailing_chars( &p[afx->buffer_pos], n-afx->buffer_pos,
667 : " \t\r\n");
668 5268 : afx->buffer_len+=afx->buffer_pos;
669 : /* the buffer is always allocated with enough space to append
670 : * the removed [CR], LF and a Nul
671 : * The reason for this complicated procedure is to keep at least
672 : * the original type of lineending - handling of the removed
673 : * trailing spaces seems to be impossible in our method
674 : * of faking a packet; either we have to use a temporary file
675 : * or calculate the hash here in this module and somehow find
676 : * a way to send the hash down the processing line (well, a special
677 : * faked packet could do the job).
678 : */
679 5268 : if( crlf )
680 0 : afx->buffer[afx->buffer_len++] = '\r';
681 5268 : afx->buffer[afx->buffer_len++] = '\n';
682 5268 : afx->buffer[afx->buffer_len] = '\0';
683 : }
684 : }
685 :
686 42 : if( lastline ) { /* write last (ending) length header */
687 16 : if(tempbuf_len<192)
688 12 : buf[len++]=tempbuf_len;
689 : else
690 : {
691 4 : buf[len++]=((tempbuf_len-192)/256) + 192;
692 4 : buf[len++]=(tempbuf_len-192) % 256;
693 : }
694 16 : memcpy(&buf[len],tempbuf,tempbuf_len);
695 16 : len+=tempbuf_len;
696 :
697 16 : rc = 0;
698 16 : afx->faked = 0;
699 16 : afx->in_cleartext = 0;
700 : /* and now read the header lines */
701 16 : afx->buffer_pos = 0;
702 : for(;;) {
703 : int i;
704 :
705 : /* read the next line (skip all truncated lines) */
706 : do {
707 26 : maxlen = MAX_LINELEN;
708 26 : afx->buffer_len = iobuf_read_line( a, &afx->buffer,
709 : &afx->buffer_size, &maxlen );
710 26 : } while( !maxlen );
711 26 : p = afx->buffer;
712 26 : n = afx->buffer_len;
713 26 : if( !n ) {
714 0 : rc = -1;
715 0 : break; /* eof */
716 : }
717 26 : i = parse_header_line( afx, p , n );
718 26 : if( i <= 0 ) {
719 16 : if( i )
720 0 : invalid_armor();
721 16 : break;
722 : }
723 10 : }
724 16 : afx->inp_checked = 1;
725 16 : afx->crc = CRCINIT;
726 16 : afx->idx = 0;
727 16 : afx->radbuf[0] = 0;
728 : }
729 :
730 42 : *retn = len;
731 42 : return rc;
732 : }
733 :
734 :
735 : static int
736 0 : invalid_crc(void)
737 : {
738 0 : if ( opt.ignore_crc_error )
739 0 : return 0;
740 0 : log_inc_errorcount();
741 0 : return gpg_error (GPG_ERR_INV_ARMOR);
742 : }
743 :
744 :
745 : static int
746 342 : radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
747 : byte *buf, size_t size )
748 : {
749 : byte val;
750 342 : int c=0, c2; /*init c because gcc is not clever enough for the continue*/
751 342 : int checkcrc=0;
752 342 : int rc = 0;
753 342 : size_t n = 0;
754 342 : int idx, i, onlypad=0;
755 : u32 crc;
756 :
757 342 : crc = afx->crc;
758 342 : idx = afx->idx;
759 342 : val = afx->radbuf[0];
760 1136898 : for( n=0; n < size; ) {
761 :
762 1136474 : if( afx->buffer_pos < afx->buffer_len )
763 1119047 : c = afx->buffer[afx->buffer_pos++];
764 : else { /* read the next line */
765 17427 : unsigned maxlen = MAX_LINELEN;
766 17427 : afx->buffer_pos = 0;
767 17427 : afx->buffer_len = iobuf_read_line( a, &afx->buffer,
768 : &afx->buffer_size, &maxlen );
769 17427 : if( !maxlen )
770 0 : afx->truncated++;
771 17427 : if( !afx->buffer_len )
772 129 : break; /* eof */
773 17298 : continue;
774 : }
775 :
776 : again:
777 1119047 : if( c == '\n' || c == ' ' || c == '\r' || c == '\t' )
778 17298 : continue;
779 1101749 : else if( c == '=' ) { /* pad character: stop */
780 : /* some mailers leave quoted-printable encoded characters
781 : * so we try to workaround this */
782 131 : if( afx->buffer_pos+2 < afx->buffer_len ) {
783 : int cc1, cc2, cc3;
784 50 : cc1 = afx->buffer[afx->buffer_pos];
785 50 : cc2 = afx->buffer[afx->buffer_pos+1];
786 50 : cc3 = afx->buffer[afx->buffer_pos+2];
787 50 : if( isxdigit(cc1) && isxdigit(cc2)
788 6 : && strchr( "=\n\r\t ", cc3 )) {
789 : /* well it seems to be the case - adjust */
790 0 : c = isdigit(cc1)? (cc1 - '0'): (ascii_toupper(cc1)-'A'+10);
791 0 : c <<= 4;
792 0 : c |= isdigit(cc2)? (cc2 - '0'): (ascii_toupper(cc2)-'A'+10);
793 0 : afx->buffer_pos += 2;
794 0 : afx->qp_detected = 1;
795 0 : goto again;
796 : }
797 : }
798 :
799 131 : if (!n)
800 2 : onlypad = 1;
801 :
802 131 : if( idx == 1 )
803 0 : buf[n++] = val;
804 131 : checkcrc++;
805 131 : break;
806 : }
807 1101618 : else if( (c = asctobin[(c2=c)]) == 255 ) {
808 0 : log_error(_("invalid radix64 character %02X skipped\n"), c2);
809 0 : continue;
810 : }
811 1101618 : switch(idx) {
812 275435 : case 0: val = c << 2; break;
813 275435 : case 1: val |= (c>>4)&3; buf[n++]=val;val=(c<<4)&0xf0;break;
814 275394 : case 2: val |= (c>>2)&15; buf[n++]=val;val=(c<<6)&0xc0;break;
815 275354 : case 3: val |= c&0x3f; buf[n++] = val; break;
816 : }
817 1101618 : idx = (idx+1) % 4;
818 : }
819 :
820 826525 : for(i=0; i < n; i++ )
821 826183 : crc = (crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ buf[i]];
822 342 : crc &= 0x00ffffff;
823 342 : afx->crc = crc;
824 342 : afx->idx = idx;
825 342 : afx->radbuf[0] = val;
826 :
827 342 : if( checkcrc ) {
828 131 : afx->any_data = 1;
829 131 : afx->inp_checked=0;
830 131 : afx->faked = 0;
831 : for(;;) { /* skip lf and pad characters */
832 415 : if( afx->buffer_pos < afx->buffer_len )
833 334 : c = afx->buffer[afx->buffer_pos++];
834 : else { /* read the next line */
835 81 : unsigned maxlen = MAX_LINELEN;
836 81 : afx->buffer_pos = 0;
837 81 : afx->buffer_len = iobuf_read_line( a, &afx->buffer,
838 : &afx->buffer_size, &maxlen );
839 81 : if( !maxlen )
840 0 : afx->truncated++;
841 81 : if( !afx->buffer_len )
842 0 : break; /* eof */
843 81 : continue;
844 : }
845 334 : if( c == '\n' || c == ' ' || c == '\r'
846 253 : || c == '\t' || c == '=' )
847 203 : continue;
848 131 : break;
849 284 : }
850 131 : if( c == -1 )
851 0 : log_error(_("premature eof (no CRC)\n"));
852 : else {
853 131 : u32 mycrc = 0;
854 131 : idx = 0;
855 : do {
856 524 : if( (c = asctobin[c]) == 255 )
857 0 : break;
858 524 : switch(idx) {
859 131 : case 0: val = c << 2; break;
860 131 : case 1: val |= (c>>4)&3; mycrc |= val << 16;val=(c<<4)&0xf0;break;
861 131 : case 2: val |= (c>>2)&15; mycrc |= val << 8;val=(c<<6)&0xc0;break;
862 131 : case 3: val |= c&0x3f; mycrc |= val; break;
863 : }
864 : for(;;) {
865 524 : if( afx->buffer_pos < afx->buffer_len )
866 524 : c = afx->buffer[afx->buffer_pos++];
867 : else { /* read the next line */
868 0 : unsigned maxlen = MAX_LINELEN;
869 0 : afx->buffer_pos = 0;
870 0 : afx->buffer_len = iobuf_read_line( a, &afx->buffer,
871 : &afx->buffer_size,
872 : &maxlen );
873 0 : if( !maxlen )
874 0 : afx->truncated++;
875 0 : if( !afx->buffer_len )
876 0 : break; /* eof */
877 0 : continue;
878 : }
879 524 : break;
880 0 : }
881 524 : if( !afx->buffer_len )
882 0 : break; /* eof */
883 524 : } while( ++idx < 4 );
884 131 : if( c == -1 ) {
885 0 : log_info(_("premature eof (in CRC)\n"));
886 0 : rc = invalid_crc();
887 : }
888 131 : else if( idx == 0 ) {
889 : /* No CRC at all is legal ("MAY") */
890 0 : rc=0;
891 : }
892 131 : else if( idx != 4 ) {
893 0 : log_info(_("malformed CRC\n"));
894 0 : rc = invalid_crc();
895 : }
896 131 : else if( mycrc != afx->crc ) {
897 0 : log_info (_("CRC error; %06lX - %06lX\n"),
898 0 : (ulong)afx->crc, (ulong)mycrc);
899 0 : rc = invalid_crc();
900 : }
901 : else {
902 131 : rc = 0;
903 : /* FIXME: Here we should emit another control packet,
904 : * so that we know in mainproc that we are processing
905 : * a clearsign message */
906 : #if 0
907 : for(rc=0;!rc;) {
908 : rc = 0 /*check_trailer( &fhdr, c )*/;
909 : if( !rc ) {
910 : if( (c=iobuf_get(a)) == -1 )
911 : rc = 2;
912 : }
913 : }
914 : if( rc == -1 )
915 : rc = 0;
916 : else if( rc == 2 ) {
917 : log_error(_("premature eof (in trailer)\n"));
918 : rc = GPG_ERR_INVALID_ARMOR;
919 : }
920 : else {
921 : log_error(_("error in trailer line\n"));
922 : rc = GPG_ERR_INVALID_ARMOR;
923 : }
924 : #endif
925 : }
926 : }
927 : }
928 :
929 342 : if( !n && !onlypad )
930 129 : rc = -1;
931 :
932 342 : *retn = n;
933 342 : return rc;
934 : }
935 :
936 : /****************
937 : * This filter is used to handle the armor stuff
938 : */
939 : static int
940 933 : armor_filter( void *opaque, int control,
941 : IOBUF a, byte *buf, size_t *ret_len)
942 : {
943 933 : size_t size = *ret_len;
944 933 : armor_filter_context_t *afx = opaque;
945 933 : int rc=0, i, c;
946 : byte radbuf[3];
947 : int idx, idx2;
948 933 : size_t n=0;
949 : u32 crc;
950 : #if 0
951 : static FILE *fp ;
952 :
953 : if( !fp ) {
954 : fp = fopen("armor.out", "w");
955 : assert(fp);
956 : }
957 : #endif
958 :
959 933 : if( DBG_FILTER )
960 0 : log_debug("armor-filter: control: %d\n", control );
961 933 : if( control == IOBUFCTRL_UNDERFLOW && afx->inp_bypass ) {
962 2 : n = 0;
963 2 : if( afx->buffer_len ) {
964 0 : for(; n < size && afx->buffer_pos < afx->buffer_len; n++ )
965 0 : buf[n++] = afx->buffer[afx->buffer_pos++];
966 0 : if( afx->buffer_pos >= afx->buffer_len )
967 0 : afx->buffer_len = 0;
968 : }
969 341 : for(; n < size; n++ ) {
970 341 : if( (c=iobuf_get(a)) == -1 )
971 2 : break;
972 339 : buf[n] = c & 0xff;
973 : }
974 2 : if( !n )
975 1 : rc = -1;
976 2 : *ret_len = n;
977 : }
978 931 : else if( control == IOBUFCTRL_UNDERFLOW ) {
979 : /* We need some space for the faked packet. The minmum
980 : * required size is the PARTIAL_CHUNK size plus a byte for the
981 : * length itself */
982 401 : if( size < PARTIAL_CHUNK+1 )
983 0 : BUG(); /* supplied buffer too short */
984 :
985 401 : if( afx->faked )
986 42 : rc = fake_packet( afx, a, &n, buf, size );
987 359 : else if( !afx->inp_checked ) {
988 261 : rc = check_input( afx, a );
989 261 : if( afx->inp_bypass ) {
990 382 : for(n=0; n < size && afx->buffer_pos < afx->buffer_len; )
991 380 : buf[n++] = afx->buffer[afx->buffer_pos++];
992 1 : if( afx->buffer_pos >= afx->buffer_len )
993 1 : afx->buffer_len = 0;
994 1 : if( !n )
995 0 : rc = -1;
996 : }
997 260 : else if( afx->faked ) {
998 16 : unsigned int hashes = afx->hashes;
999 : const byte *sesmark;
1000 : size_t sesmarklen;
1001 :
1002 16 : sesmark = get_session_marker( &sesmarklen );
1003 16 : if ( sesmarklen > 20 )
1004 0 : BUG();
1005 :
1006 : /* the buffer is at least 15+n*15 bytes long, so it
1007 : * is easy to construct the packets */
1008 :
1009 16 : hashes &= 1|2|8|16|32|64;
1010 16 : if( !hashes ) {
1011 0 : hashes |= 2; /* Default to SHA-1. */
1012 : }
1013 16 : n=0;
1014 : /* First a gpg control packet... */
1015 16 : buf[n++] = 0xff; /* new format, type 63, 1 length byte */
1016 16 : n++; /* see below */
1017 16 : memcpy(buf+n, sesmark, sesmarklen ); n+= sesmarklen;
1018 16 : buf[n++] = CTRLPKT_CLEARSIGN_START;
1019 16 : buf[n++] = afx->not_dash_escaped? 0:1; /* sigclass */
1020 16 : if( hashes & 1 )
1021 0 : buf[n++] = DIGEST_ALGO_RMD160;
1022 16 : if( hashes & 2 )
1023 16 : buf[n++] = DIGEST_ALGO_SHA1;
1024 16 : if( hashes & 8 )
1025 0 : buf[n++] = DIGEST_ALGO_SHA224;
1026 16 : if( hashes & 16 )
1027 0 : buf[n++] = DIGEST_ALGO_SHA256;
1028 16 : if( hashes & 32 )
1029 0 : buf[n++] = DIGEST_ALGO_SHA384;
1030 16 : if( hashes & 64 )
1031 0 : buf[n++] = DIGEST_ALGO_SHA512;
1032 16 : buf[1] = n - 2;
1033 :
1034 : /* ...followed by an invented plaintext packet.
1035 : Amusingly enough, this packet is not compliant with
1036 : 2440 as the initial partial length is less than 512
1037 : bytes. Of course, we'll accept it anyway ;) */
1038 :
1039 16 : buf[n++] = 0xCB; /* new packet format, type 11 */
1040 16 : buf[n++] = 0xE1; /* 2^1 == 2 bytes */
1041 16 : buf[n++] = 't'; /* canonical text mode */
1042 16 : buf[n++] = 0; /* namelength */
1043 16 : buf[n++] = 0xE2; /* 2^2 == 4 more bytes */
1044 16 : memset(buf+n, 0, 4); /* timestamp */
1045 16 : n += 4;
1046 : }
1047 244 : else if( !rc )
1048 244 : rc = radix64_read( afx, a, &n, buf, size );
1049 : }
1050 : else
1051 98 : rc = radix64_read( afx, a, &n, buf, size );
1052 : #if 0
1053 : if( n )
1054 : if( fwrite(buf, n, 1, fp ) != 1 )
1055 : BUG();
1056 : #endif
1057 401 : *ret_len = n;
1058 : }
1059 530 : else if( control == IOBUFCTRL_FLUSH && !afx->cancel ) {
1060 168 : if( !afx->status ) { /* write the header line */
1061 : const char *s;
1062 51 : strlist_t comment=opt.comments;
1063 :
1064 51 : if( afx->what >= DIM(head_strings) )
1065 0 : log_bug("afx->what=%d", afx->what);
1066 51 : iobuf_writestr(a, "-----");
1067 51 : iobuf_writestr(a, head_strings[afx->what] );
1068 51 : iobuf_writestr(a, "-----" );
1069 51 : iobuf_writestr(a,afx->eol);
1070 51 : if (opt.emit_version)
1071 : {
1072 51 : iobuf_writestr (a, "Version: "GNUPG_NAME" v");
1073 102 : for (s=VERSION; *s && *s != '.'; s++)
1074 51 : iobuf_writebyte (a, *s);
1075 51 : if (opt.emit_version > 1 && *s)
1076 : {
1077 0 : iobuf_writebyte (a, *s++);
1078 0 : for (; *s && *s != '.'; s++)
1079 0 : iobuf_writebyte (a, *s);
1080 0 : if (opt.emit_version > 2)
1081 : {
1082 0 : for (; *s && *s != '-' && !spacep (s); s++)
1083 0 : iobuf_writebyte (a, *s);
1084 0 : if (opt.emit_version > 3)
1085 0 : iobuf_writestr (a, " (" PRINTABLE_OS_NAME ")");
1086 : }
1087 : }
1088 51 : iobuf_writestr(a,afx->eol);
1089 : }
1090 :
1091 : /* write the comment strings */
1092 51 : for(s=comment->d;comment;comment=comment->next,s=comment->d)
1093 : {
1094 0 : iobuf_writestr(a, "Comment: " );
1095 0 : for( ; *s; s++ )
1096 : {
1097 0 : if( *s == '\n' )
1098 0 : iobuf_writestr(a, "\\n" );
1099 0 : else if( *s == '\r' )
1100 0 : iobuf_writestr(a, "\\r" );
1101 0 : else if( *s == '\v' )
1102 0 : iobuf_writestr(a, "\\v" );
1103 : else
1104 0 : iobuf_put(a, *s );
1105 : }
1106 :
1107 0 : iobuf_writestr(a,afx->eol);
1108 : }
1109 :
1110 51 : if ( afx->hdrlines ) {
1111 86 : for ( s = afx->hdrlines; *s; s++ ) {
1112 : #ifdef HAVE_DOSISH_SYSTEM
1113 : if ( *s == '\n' )
1114 : iobuf_put( a, '\r');
1115 : #endif
1116 84 : iobuf_put(a, *s );
1117 : }
1118 : }
1119 :
1120 51 : iobuf_writestr(a,afx->eol);
1121 51 : afx->status++;
1122 51 : afx->idx = 0;
1123 51 : afx->idx2 = 0;
1124 51 : afx->crc = CRCINIT;
1125 :
1126 : }
1127 168 : crc = afx->crc;
1128 168 : idx = afx->idx;
1129 168 : idx2 = afx->idx2;
1130 243 : for(i=0; i < idx; i++ )
1131 75 : radbuf[i] = afx->radbuf[i];
1132 :
1133 506156 : for(i=0; i < size; i++ )
1134 505988 : crc = (crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ buf[i]];
1135 168 : crc &= 0x00ffffff;
1136 :
1137 506156 : for( ; size; buf++, size-- ) {
1138 505988 : radbuf[idx++] = *buf;
1139 505988 : if( idx > 2 ) {
1140 168649 : idx = 0;
1141 168649 : c = bintoasc[(*radbuf >> 2) & 077];
1142 168649 : iobuf_put(a, c);
1143 168649 : c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
1144 168649 : iobuf_put(a, c);
1145 168649 : c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
1146 168649 : iobuf_put(a, c);
1147 168649 : c = bintoasc[radbuf[2]&077];
1148 168649 : iobuf_put(a, c);
1149 168649 : if( ++idx2 >= (64/4) )
1150 : { /* pgp doesn't like 72 here */
1151 10514 : iobuf_writestr(a,afx->eol);
1152 10514 : idx2=0;
1153 : }
1154 : }
1155 : }
1156 284 : for(i=0; i < idx; i++ )
1157 116 : afx->radbuf[i] = radbuf[i];
1158 168 : afx->idx = idx;
1159 168 : afx->idx2 = idx2;
1160 168 : afx->crc = crc;
1161 : }
1162 362 : else if( control == IOBUFCTRL_INIT )
1163 : {
1164 181 : if( !is_initialized )
1165 180 : initialize();
1166 :
1167 : /* Figure out what we're using for line endings if the caller
1168 : didn't specify. */
1169 181 : if(afx->eol[0]==0)
1170 : {
1171 : #ifdef HAVE_DOSISH_SYSTEM
1172 : afx->eol[0]='\r';
1173 : afx->eol[1]='\n';
1174 : #else
1175 181 : afx->eol[0]='\n';
1176 : #endif
1177 : }
1178 : }
1179 181 : else if( control == IOBUFCTRL_CANCEL ) {
1180 0 : afx->cancel = 1;
1181 : }
1182 181 : else if( control == IOBUFCTRL_FREE ) {
1183 181 : if( afx->cancel )
1184 : ;
1185 181 : else if( afx->status ) { /* pad, write cecksum, and bottom line */
1186 51 : crc = afx->crc;
1187 51 : idx = afx->idx;
1188 51 : idx2 = afx->idx2;
1189 51 : if( idx ) {
1190 27 : c = bintoasc[(afx->radbuf[0]>>2)&077];
1191 27 : iobuf_put(a, c);
1192 27 : if( idx == 1 ) {
1193 13 : c = bintoasc[((afx->radbuf[0] << 4) & 060) & 077];
1194 13 : iobuf_put(a, c);
1195 13 : iobuf_put(a, '=');
1196 13 : iobuf_put(a, '=');
1197 : }
1198 : else { /* 2 */
1199 28 : c = bintoasc[(((afx->radbuf[0]<<4)&060)
1200 14 : |((afx->radbuf[1]>>4)&017))&077];
1201 14 : iobuf_put(a, c);
1202 14 : c = bintoasc[((afx->radbuf[1] << 2) & 074) & 077];
1203 14 : iobuf_put(a, c);
1204 14 : iobuf_put(a, '=');
1205 : }
1206 27 : if( ++idx2 >= (64/4) )
1207 : { /* pgp doesn't like 72 here */
1208 3 : iobuf_writestr(a,afx->eol);
1209 3 : idx2=0;
1210 : }
1211 : }
1212 : /* may need a linefeed */
1213 51 : if( idx2 )
1214 47 : iobuf_writestr(a,afx->eol);
1215 : /* write the CRC */
1216 51 : iobuf_put(a, '=');
1217 51 : radbuf[0] = crc >>16;
1218 51 : radbuf[1] = crc >> 8;
1219 51 : radbuf[2] = crc;
1220 51 : c = bintoasc[(*radbuf >> 2) & 077];
1221 51 : iobuf_put(a, c);
1222 51 : c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
1223 51 : iobuf_put(a, c);
1224 51 : c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
1225 51 : iobuf_put(a, c);
1226 51 : c = bintoasc[radbuf[2]&077];
1227 51 : iobuf_put(a, c);
1228 51 : iobuf_writestr(a,afx->eol);
1229 : /* and the the trailer */
1230 51 : if( afx->what >= DIM(tail_strings) )
1231 0 : log_bug("afx->what=%d", afx->what);
1232 51 : iobuf_writestr(a, "-----");
1233 51 : iobuf_writestr(a, tail_strings[afx->what] );
1234 51 : iobuf_writestr(a, "-----" );
1235 51 : iobuf_writestr(a,afx->eol);
1236 : }
1237 130 : else if( !afx->any_data && !afx->inp_bypass ) {
1238 1 : log_error(_("no valid OpenPGP data found.\n"));
1239 1 : afx->no_openpgp_data = 1;
1240 1 : write_status_text( STATUS_NODATA, "1" );
1241 : }
1242 181 : if( afx->truncated )
1243 0 : log_info(_("invalid armor: line longer than %d characters\n"),
1244 : MAX_LINELEN );
1245 : /* issue an error to enforce dissemination of correct software */
1246 181 : if( afx->qp_detected )
1247 0 : log_error(_("quoted printable character in armor - "
1248 : "probably a buggy MTA has been used\n") );
1249 181 : xfree( afx->buffer );
1250 181 : afx->buffer = NULL;
1251 181 : release_armor_context (afx);
1252 : }
1253 0 : else if( control == IOBUFCTRL_DESC )
1254 0 : *(char**)buf = "armor_filter";
1255 933 : return rc;
1256 : }
1257 :
1258 :
1259 : /****************
1260 : * create a radix64 encoded string.
1261 : */
1262 : char *
1263 6 : make_radix64_string( const byte *data, size_t len )
1264 : {
1265 : char *buffer, *p;
1266 :
1267 6 : buffer = p = xmalloc( (len+2)/3*4 + 1 );
1268 66 : for( ; len >= 3 ; len -= 3, data += 3 ) {
1269 60 : *p++ = bintoasc[(data[0] >> 2) & 077];
1270 60 : *p++ = bintoasc[(((data[0] <<4)&060)|((data[1] >> 4)&017))&077];
1271 60 : *p++ = bintoasc[(((data[1]<<2)&074)|((data[2]>>6)&03))&077];
1272 60 : *p++ = bintoasc[data[2]&077];
1273 : }
1274 6 : if( len == 2 ) {
1275 6 : *p++ = bintoasc[(data[0] >> 2) & 077];
1276 6 : *p++ = bintoasc[(((data[0] <<4)&060)|((data[1] >> 4)&017))&077];
1277 6 : *p++ = bintoasc[((data[1]<<2)&074)];
1278 : }
1279 0 : else if( len == 1 ) {
1280 0 : *p++ = bintoasc[(data[0] >> 2) & 077];
1281 0 : *p++ = bintoasc[(data[0] <<4)&060];
1282 : }
1283 6 : *p = 0;
1284 6 : return buffer;
1285 : }
1286 :
1287 :
1288 : /***********************************************
1289 : * For the pipemode command we can't use the armor filter for various
1290 : * reasons, so we use this new unarmor_pump stuff to remove the armor
1291 : */
1292 :
1293 : enum unarmor_state_e {
1294 : STA_init = 0,
1295 : STA_bypass,
1296 : STA_wait_newline,
1297 : STA_wait_dash,
1298 : STA_first_dash,
1299 : STA_compare_header,
1300 : STA_found_header_wait_newline,
1301 : STA_skip_header_lines,
1302 : STA_skip_header_lines_non_ws,
1303 : STA_read_data,
1304 : STA_wait_crc,
1305 : STA_read_crc,
1306 : STA_ready
1307 : };
1308 :
1309 : struct unarmor_pump_s {
1310 : enum unarmor_state_e state;
1311 : byte val;
1312 : int checkcrc;
1313 : int pos; /* counts from 0..3 */
1314 : u32 crc;
1315 : u32 mycrc; /* the one store in the data */
1316 : };
1317 :
1318 :
1319 :
1320 : UnarmorPump
1321 0 : unarmor_pump_new (void)
1322 : {
1323 : UnarmorPump x;
1324 :
1325 0 : if( !is_initialized )
1326 0 : initialize();
1327 0 : x = xmalloc_clear (sizeof *x);
1328 0 : return x;
1329 : }
1330 :
1331 : void
1332 0 : unarmor_pump_release (UnarmorPump x)
1333 : {
1334 0 : xfree (x);
1335 0 : }
1336 :
1337 : /*
1338 : * Get the next character from the ascii armor taken from the IOBUF
1339 : * created earlier by unarmor_pump_new().
1340 : * Return: c = Character
1341 : * 256 = ignore this value
1342 : * -1 = End of current armor
1343 : * -2 = Premature EOF (not used)
1344 : * -3 = Invalid armor
1345 : */
1346 : int
1347 0 : unarmor_pump (UnarmorPump x, int c)
1348 : {
1349 0 : int rval = 256; /* default is to ignore the return value */
1350 :
1351 0 : switch (x->state) {
1352 : case STA_init:
1353 : {
1354 : byte tmp[1];
1355 0 : tmp[0] = c;
1356 0 : if ( is_armored (tmp) )
1357 0 : x->state = c == '-'? STA_first_dash : STA_wait_newline;
1358 : else {
1359 0 : x->state = STA_bypass;
1360 0 : return c;
1361 : }
1362 : }
1363 0 : break;
1364 : case STA_bypass:
1365 0 : return c; /* return here to avoid crc calculation */
1366 : case STA_wait_newline:
1367 0 : if (c == '\n')
1368 0 : x->state = STA_wait_dash;
1369 0 : break;
1370 : case STA_wait_dash:
1371 0 : x->state = c == '-'? STA_first_dash : STA_wait_newline;
1372 0 : break;
1373 : case STA_first_dash: /* just need for initalization */
1374 0 : x->pos = 0;
1375 0 : x->state = STA_compare_header;
1376 : case STA_compare_header:
1377 0 : if ( "-----BEGIN PGP SIGNATURE-----"[++x->pos] == c ) {
1378 0 : if ( x->pos == 28 )
1379 0 : x->state = STA_found_header_wait_newline;
1380 : }
1381 : else
1382 0 : x->state = c == '\n'? STA_wait_dash : STA_wait_newline;
1383 0 : break;
1384 : case STA_found_header_wait_newline:
1385 : /* to make CR,LF issues easier we simply allow for white space
1386 : behind the 5 dashes */
1387 0 : if ( c == '\n' )
1388 0 : x->state = STA_skip_header_lines;
1389 0 : else if ( c != '\r' && c != ' ' && c != '\t' )
1390 0 : x->state = STA_wait_dash; /* garbage after the header line */
1391 0 : break;
1392 : case STA_skip_header_lines:
1393 : /* i.e. wait for one empty line */
1394 0 : if ( c == '\n' ) {
1395 0 : x->state = STA_read_data;
1396 0 : x->crc = CRCINIT;
1397 0 : x->val = 0;
1398 0 : x->pos = 0;
1399 : }
1400 0 : else if ( c != '\r' && c != ' ' && c != '\t' )
1401 0 : x->state = STA_skip_header_lines_non_ws;
1402 0 : break;
1403 : case STA_skip_header_lines_non_ws:
1404 : /* like above but we already encountered non white space */
1405 0 : if ( c == '\n' )
1406 0 : x->state = STA_skip_header_lines;
1407 0 : break;
1408 : case STA_read_data:
1409 : /* fixme: we don't check for the trailing dash lines but rely
1410 : * on the armor stop characters */
1411 0 : if( c == '\n' || c == ' ' || c == '\r' || c == '\t' )
1412 : break; /* skip all kind of white space */
1413 :
1414 0 : if( c == '=' ) { /* pad character: stop */
1415 0 : if( x->pos == 1 ) /* in this case val has some value */
1416 0 : rval = x->val;
1417 0 : x->state = STA_wait_crc;
1418 0 : break;
1419 : }
1420 :
1421 : {
1422 : int c2;
1423 0 : if( (c = asctobin[(c2=c)]) == 255 ) {
1424 0 : log_error(_("invalid radix64 character %02X skipped\n"), c2);
1425 0 : break;
1426 : }
1427 : }
1428 :
1429 0 : switch(x->pos) {
1430 : case 0:
1431 0 : x->val = c << 2;
1432 0 : break;
1433 : case 1:
1434 0 : x->val |= (c>>4)&3;
1435 0 : rval = x->val;
1436 0 : x->val = (c<<4)&0xf0;
1437 0 : break;
1438 : case 2:
1439 0 : x->val |= (c>>2)&15;
1440 0 : rval = x->val;
1441 0 : x->val = (c<<6)&0xc0;
1442 0 : break;
1443 : case 3:
1444 0 : x->val |= c&0x3f;
1445 0 : rval = x->val;
1446 0 : break;
1447 : }
1448 0 : x->pos = (x->pos+1) % 4;
1449 0 : break;
1450 : case STA_wait_crc:
1451 0 : if( c == '\n' || c == ' ' || c == '\r' || c == '\t' || c == '=' )
1452 : break; /* skip ws and pad characters */
1453 : /* assume that we are at the next line */
1454 0 : x->state = STA_read_crc;
1455 0 : x->pos = 0;
1456 0 : x->mycrc = 0;
1457 : case STA_read_crc:
1458 0 : if( (c = asctobin[c]) == 255 ) {
1459 0 : rval = -1; /* ready */
1460 0 : if( x->crc != x->mycrc ) {
1461 0 : log_info (_("CRC error; %06lX - %06lX\n"),
1462 0 : (ulong)x->crc, (ulong)x->mycrc);
1463 0 : if ( invalid_crc() )
1464 0 : rval = -3;
1465 : }
1466 0 : x->state = STA_ready; /* not sure whether this is correct */
1467 0 : break;
1468 : }
1469 :
1470 0 : switch(x->pos) {
1471 : case 0:
1472 0 : x->val = c << 2;
1473 0 : break;
1474 : case 1:
1475 0 : x->val |= (c>>4)&3;
1476 0 : x->mycrc |= x->val << 16;
1477 0 : x->val = (c<<4)&0xf0;
1478 0 : break;
1479 : case 2:
1480 0 : x->val |= (c>>2)&15;
1481 0 : x->mycrc |= x->val << 8;
1482 0 : x->val = (c<<6)&0xc0;
1483 0 : break;
1484 : case 3:
1485 0 : x->val |= c&0x3f;
1486 0 : x->mycrc |= x->val;
1487 0 : break;
1488 : }
1489 0 : x->pos = (x->pos+1) % 4;
1490 0 : break;
1491 : case STA_ready:
1492 0 : rval = -1;
1493 0 : break;
1494 : }
1495 :
1496 0 : if ( !(rval & ~255) ) { /* compute the CRC */
1497 0 : x->crc = (x->crc << 8) ^ crc_table[((x->crc >> 16)&0xff) ^ rval];
1498 0 : x->crc &= 0x00ffffff;
1499 : }
1500 :
1501 0 : return rval;
1502 : }
|