aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--g10/armor.c542
1 files changed, 323 insertions, 219 deletions
diff --git a/g10/armor.c b/g10/armor.c
index 6a432d318..3a6fc41f3 100644
--- a/g10/armor.c
+++ b/g10/armor.c
@@ -49,25 +49,30 @@ static byte bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
static byte asctobin[256]; /* runtime initialized */
static int is_initialized;
+
typedef enum {
- fhdrINIT=0,
- fhdrLF,
- fhdrWAIT,
- fhdrWAITINFO,
- fhdrWAITCLEARSIG,
- fhdrDASH,
- fhdrHEAD,
- fhdrDASH2,
- fhdrINFO
+ fhdrHASArmor,
+ fhdrNOArmor,
+ fhdrINIT,
+ fhdrINITCont,
+ fhdrINITSkip,
+ fhdrCHECKBegin,
+ fhdrWAITHeader,
+ fhdrWAITClearsig,
+ fhdrSKIPHeader,
+ fhdrCLEARSIG,
+ fhdrREADClearsig,
+ fhdrEMPTYClearsig,
+ fhdrCHECKClearsig,
+ fhdrCHECKClearsig2,
+ fhdrREADClearsigNext,
+ fhdrENDClearsig,
+ fhdrTEXT,
+ fhdrERROR,
+ fhdrERRORShow,
+ fhdrEOF
} fhdr_state_t;
-struct fhdr_struct {
- fhdr_state_t state;
- int count;
- int hdr_line; /* number of the header line */
- char buf[256];
-};
-
/* if we encounter this armor string with this index, go
* into a mode, which fakes packets and wait for the next armor */
@@ -87,6 +92,10 @@ static char *tail_strings[] = {
};
+static fhdr_state_t find_header( fhdr_state_t state,
+ byte *buf, size_t *r_buflen, IOBUF a, size_t n);
+
+
static void
initialize(void)
{
@@ -124,18 +133,14 @@ initialize(void)
* Returns: True if it seems to be armored
*/
static int
-is_armored( byte *buf, size_t len )
+is_armored( byte *buf )
{
int ctb, pkttype;
- if( len < 28 )
- return 0; /* not even enough space for the "---BEGIN"... */
-
ctb = *buf;
if( !(ctb & 0x80) )
return 1; /* invalid packet: assume it is armored */
pkttype = ctb & 0x40 ? (ctb & 0x3f) : ((ctb>>2)&0xf);
- /*lenbytes = (ctb & 0x40) || ((ctb&3)==3)? 0 : (1<<(ctb & 3));*/
switch( pkttype ) {
case PKT_PUBLIC_CERT:
case PKT_SECRET_CERT:
@@ -152,120 +157,246 @@ is_armored( byte *buf, size_t len )
}
-
-
-static int
-find_header( struct fhdr_struct *fhdr, int c )
+/****************
+ * parse an ascii armor.
+ * Returns: the state,
+ * the remaining bytes in BUF are returned in RBUFLEN.
+ */
+static fhdr_state_t
+find_header( fhdr_state_t state, byte *buf, size_t *r_buflen, IOBUF a, size_t n)
{
- int i;
+ int c, i;
const char *s;
+ char *p;
+ size_t buflen;
+ int cont;
+ int clearsig=0;
+ int hdr_line=0;
+
+ buflen = *r_buflen;
+ assert(buflen >= 100 );
+ buflen--;
+
+ do {
+ switch( state ) {
+ case fhdrHASArmor:
+ /* read 28 bytes, which is the bare minimum for a BEGIN...
+ * and check wether this has a Armor. */
+ c = 0;
+ for(n=0; n < 28 && (c=iobuf_get(a)) != -1 && c != '\n'; )
+ buf[n++] = c;
+ if( n < 28 || c == -1 )
+ state = fhdrNOArmor; /* too short */
+ else if( !is_armored( buf ) )
+ state = fhdrNOArmor;
+ else
+ state = fhdrINITCont;
+ break;
- if( c == '\n' ) {
- switch( fhdr->state ) {
- case fhdrINFO:
- if( !fhdr->count )
- return 1; /* blank line: data starts with the next line */
- fhdr->buf[fhdr->count] = 0;
- log_debug("armor line: '%s'\n", fhdr->buf );
- /* fall through */
- case fhdrWAITINFO:
- fhdr->state = fhdrINFO;
- fhdr->count = 0;
+ case fhdrINIT: /* read some stuff into buffer */
+ n = 0;
+ case fhdrINITCont: /* read more stuff into buffer */
+ c = 0;
+ for(; n < buflen && (c=iobuf_get(a)) != -1 && c != '\n'; )
+ buf[n++] = c;
+ state = c == '\n' ? fhdrCHECKBegin :
+ c == -1 ? fhdrEOF : fhdrINITSkip;
break;
- case fhdrWAITCLEARSIG:
- if( fhdr->count++ == 1 ) /* skip the empty line */
- return 1; /* clear signed text follows */
- else if( fhdr->count > 1 )
- fhdr->state = fhdrWAIT; /* was not valid */
+
+ case fhdrINITSkip:
+ while( (c=iobuf_get(a)) != -1 && c != '\n' )
+ ;
+ state = c == -1? fhdrEOF : fhdrINIT;
break;
- default:
- fhdr->state = fhdrLF;
+
+ case fhdrSKIPHeader:
+ while( (c=iobuf_get(a)) != -1 && c != '\n' )
+ ;
+ state = c == -1? fhdrEOF : fhdrWAITHeader;
break;
- }
- }
- else {
- switch( fhdr->state ) {
- case fhdrINIT:
- case fhdrLF:
- if( c == '-' ) {
- fhdr->state = fhdrDASH;
- fhdr->count = 1;
+
+ case fhdrWAITHeader: /* wait for Header lines */
+ c = 0;
+ for(n=0; n < buflen && (c=iobuf_get(a)) != -1 && c != '\n'; )
+ buf[n++] = c;
+ buf[n] = 0;
+ if( n < buflen || c == '\n' ) {
+ if( n && buf[0] != '\r') { /* maybe a header */
+ if( strchr( buf, ':') ) { /* yes */
+ log_debug("armor header: ");
+ print_string( stderr, buf, n );
+ putc('\n', stderr);
+ state = fhdrWAITHeader;
+ }
+ else
+ state = fhdrTEXT;
+ }
+ else if( !n || (buf[0] == '\r' && !buf[1]) ) { /* empty line */
+ if( clearsig )
+ state = fhdrWAITClearsig;
+ else {
+ /* this is not really correct: if we do not have
+ * a clearsig and not armor lines we are not allowed
+ * to have an empty line */
+ n = 0;
+ state = fhdrTEXT;
+ }
+ }
+ else {
+ log_debug("invalid armor header: ");
+ print_string( stderr, buf, n );
+ putc('\n', stderr);
+ state = fhdrERROR;
+ }
+ }
+ else if( c != -1 ) {
+ if( strchr( buf, ':') ) { /* buffer to short, but this is okay*/
+ log_debug("armor header: ");
+ print_string( stderr, buf, n );
+ fputs("[...]\n", stderr); /* indicate it is truncated */
+ state = fhdrSKIPHeader; /* skip rest of line */
+ }
+ else /* line too long */
+ state = fhdrERROR;
}
else
- fhdr->state = fhdrWAIT;
+ state = fhdrEOF;
break;
- case fhdrWAIT:
- case fhdrWAITINFO:
- case fhdrWAITCLEARSIG:
+
+ case fhdrWAITClearsig: /* skip all empty lines (for clearsig) */
+ c = 0;
+ for(n=0; n < buflen && (c=iobuf_get(a)) != -1 && c != '\n'; )
+ buf[n++] = c;
+ if( n < buflen || c == '\n' ) {
+ buf[n] = 0;
+ if( !n || (buf[0]=='\r' && !buf[1]) ) /* empty line */
+ ;
+ else
+ state = fhdrTEXT;
+ }
+ else
+ state = fhdrEOF;
break;
- case fhdrDASH:
- if( c == '-' ) {
- if( ++fhdr->count == 5 ) {
- fhdr->state = fhdrHEAD;
- fhdr->count = 0;
- }
+
+ case fhdrENDClearsig:
+ case fhdrCHECKBegin:
+ state = state == fhdrCHECKBegin ? fhdrINITSkip : fhdrERRORShow;
+ if( n < 15 )
+ break; /* too short */
+ if( memcmp( buf, "-----", 5 ) )
+ break;
+ buf[n] = 0;
+ p = strstr(buf+5, "-----");
+ if( !p )
+ break;
+ *p = 0;
+ p += 5;
+ if( *p == '\r' )
+ p++;
+ if( *p )
+ break; /* garbage after dashes */
+ p = buf+5;
+ for(i=0; (s=head_strings[i]); i++ )
+ if( !strcmp(s, p) )
+ break;
+ if( !s )
+ break; /* unknown begin line */
+ /* found the begin line */
+ hdr_line = i;
+ state = fhdrWAITHeader;
+ if( hdr_line == BEGIN_SIGNED_MSG_IDX )
+ clearsig = 1;
+ log_debug("armor: %s\n", head_strings[hdr_line]);
+ break;
+
+ case fhdrCLEARSIG:
+ case fhdrEMPTYClearsig:
+ case fhdrREADClearsig:
+ /* we are at the start of a line: read a clearsig into the buffer
+ * we have to look for a the header line or dashd escaped text*/
+ n = 0;
+ c = 0;
+ for(; n < buflen && (c=iobuf_get(a)) != -1 && c != '\n'; )
+ buf[n++] = c;
+ buf[n] = 0;
+ if( c == -1 )
+ state = fhdrEOF;
+ else if( !n || ( buf[0]=='\r' && !buf[1] ) ) {
+ state = fhdrEMPTYClearsig;
+ /* FIXME: handle it */
}
+ else if( c == '\n' )
+ state = fhdrCHECKClearsig2;
else
- fhdr->state = fhdrWAIT;
+ state = fhdrCHECKClearsig;
break;
- case fhdrHEAD:
- if( c != '-' ) {
- if( fhdr->count < DIM(fhdr->buf)-1 )
- fhdr->buf[fhdr->count++] = c;
+
+ case fhdrCHECKClearsig:
+ case fhdrCHECKClearsig2:
+ /* check the clearsig line */
+ if( n > 15 && !memcmp(buf, "-----", 5 ) )
+ state = fhdrENDClearsig;
+ else if( buf[0] == '-' && buf[1] == ' ' ) {
+ /* dash escaped line */
+ if( buf[2] == '-' || ( n > 6 && !memcmp(buf+2, "From ", 5))) {
+ for(i=2; i < n; i++ )
+ buf[i-2] = buf[i];
+ n -= 2;
+ buf[n] = 0; /* not really needed */
+ state = state == fhdrCHECKClearsig2 ?
+ fhdrREADClearsig : fhdrREADClearsigNext;
+ /* FIXME: add the lf to the buffer */
+ }
+ else {
+ log_debug("invalid dash escaped line: ");
+ print_string( stderr, buf, n );
+ putc('\n', stderr);
+ state = fhdrERROR;
+ }
}
else {
- fhdr->buf[fhdr->count] = 0;
- for(i=0; (s=head_strings[i]); i++ )
- if( !strcmp(s,fhdr->buf) )
- break;
- if( s ) { /* found string; wait for trailing dashes */
- fhdr->hdr_line = i;
- fhdr->state = fhdrDASH2;
- fhdr->count = 1;
- }
- else
- fhdr->state = fhdrWAIT;
+ state = state == fhdrCHECKClearsig2 ?
+ fhdrREADClearsig : fhdrREADClearsigNext;
+ /* FIXME: add the lf to the buffer */
}
break;
- case fhdrDASH2:
- if( c == '-' ) {
- if( ++fhdr->count == 5 ) {
- fhdr->state = fhdrWAITINFO;
- log_debug("armor head: '%s'\n",
- head_strings[fhdr->hdr_line]);
- fhdr->state = fhdr->hdr_line == BEGIN_SIGNED_MSG_IDX
- ? fhdrWAITCLEARSIG : fhdrWAITINFO;
- if( fhdr->state == fhdrWAITCLEARSIG )
- fhdr->count = 0;
- }
- }
- else
- fhdr->state = fhdrWAIT;
+ case fhdrREADClearsigNext:
+ /* Read to the end of the line, do not care about checking
+ * for dashed escaped text of headers */
break;
- case fhdrINFO:
- if( fhdr->count < DIM(fhdr->buf)-1 )
- fhdr->buf[fhdr->count++] = c;
+ case fhdrERRORShow:
+ log_debug("invalid clear text header: ");
+ print_string( stderr, buf, n );
+ putc('\n', stderr);
+ state = fhdrERROR;
break;
- default: abort();
+ default: BUG();
}
- }
- return 0;
-}
+ switch( state ) {
+ case fhdrINIT:
+ case fhdrINITCont:
+ case fhdrINITSkip:
+ case fhdrCHECKBegin:
+ case fhdrWAITHeader:
+ case fhdrWAITClearsig:
+ case fhdrSKIPHeader:
+ case fhdrEMPTYClearsig:
+ case fhdrCHECKClearsig:
+ case fhdrCHECKClearsig2:
+ case fhdrERRORShow:
+ cont = 1;
+ break;
+ default: cont = 0;
+ }
+ } while( cont );
-/****************
- * check wether the trailer is okay.
- * Returns: 0 := still in trailer
- * -1 := Okay
- * 1 := Error in trailer
- */
-static int
-check_trailer( struct fhdr_struct *fhdr, int c )
-{
- return -1;
- /* FIXME: implement this ! */
+ if( clearsig && state == fhdrTEXT )
+ state = fhdrCLEARSIG;
+ *r_buflen = n;
+ return state;
}
@@ -274,59 +405,45 @@ static int
check_input( armor_filter_context_t *afx, IOBUF a )
{
int rc = 0;
- int c;
- size_t n = 0, nn=0;
- struct fhdr_struct fhdr;
+ size_t n;
+ fhdr_state_t state = afx->parse_state;
- assert( DIM(afx->helpbuf) >= 50 );
- memset( &fhdr, 0, sizeof(fhdr) );
+ if( state != fhdrENDClearsig )
+ state = fhdrHASArmor;
- /* read a couple of bytes */
- for( n=0; n < DIM(afx->helpbuf); n++ ) {
- if( (c=iobuf_get(a)) == -1 )
- break;
- afx->helpbuf[n] = c & 0xff;
- }
+ n = DIM(afx->helpbuf);
+ state = find_header( state, afx->helpbuf, &n, a, afx->helplen );
+ switch( state ) {
+ case fhdrNOArmor:
+ afx->inp_checked = 1;
+ afx->inp_bypass = 1;
+ afx->helplen = n;
+ break;
- if( !n )
+ case fhdrERROR:
+ case fhdrEOF:
rc = -1;
- else if( is_armored( afx->helpbuf, n ) ) {
- for(nn=0; nn < n; nn++ )
- if( find_header( &fhdr, afx->helpbuf[nn] ) )
- break;
- if( nn == n ) { /* continue read */
- while( (c=iobuf_get(a)) != -1 )
- if( find_header( &fhdr, c ) )
- break;
- if( c == -1 )
- rc = -1; /* eof */
- }
- if( !rc && fhdr.hdr_line == BEGIN_SIGNED_MSG_IDX ) {
- /* start fake package mode (for clear signatures) */
- nn++;
- afx->helplen = n;
- afx->helpidx = nn;
- afx->templen = 0;
- afx->tempidx = 0;
- afx->fake = m_alloc_clear( sizeof(struct fhdr_struct) );
- }
- else if( !rc ) {
- /* next byte to read or helpbuf[nn+1]
- * is the first rad64 byte */
- nn++;
- afx->inp_checked = 1;
- afx->crc = CRCINIT;
- afx->idx = 0;
- afx->radbuf[0] = 0;
- afx->helplen = n;
- afx->helpidx = nn;
- }
- }
- else {
+ break;
+
+ case fhdrCLEARSIG: /* start fake package mode (for clear signatures) */
+ afx->helplen = n;
+ afx->helpidx = 0;
+ afx->faked = 1;
+ break;
+
+ case fhdrTEXT:
+ afx->helplen = n;
+ afx->helpidx = 0;
afx->inp_checked = 1;
- afx->inp_bypass = 1;
+ afx->crc = CRCINIT;
+ afx->idx = 0;
+ afx->radbuf[0] = 0;
+ break;
+
+ default: BUG();
}
+ afx->parse_state = state;
return rc;
}
@@ -338,71 +455,61 @@ fake_packet( armor_filter_context_t *afx, IOBUF a,
size_t *retn, byte *buf, size_t size )
{
int rc = 0;
- int c;
- size_t n = 0;
- struct fhdr_struct *fhdr = afx->fake;
- byte *helpbuf = afx->helpbuf;
- int helpidx = afx->helpidx;
- int helplen = afx->helplen;
- byte *tempbuf = afx->tempbuf;
- int tempidx = afx->tempidx;
- int templen = afx->templen;
-
- /* FIXME: have to read one ahead or do some other mimic to
- * get rid of the lf before the "begin signed message"
- */
+ size_t len = 0;
+ size_t n, nn;
+ fhdr_state_t state = afx->parse_state;
+
size = 100; /* FIXME: only used for testing (remove it) */
- n = 2; /* reserve 2 bytes for the length header */
- while( n < size-2 ) { /* and 2 for the term header */
- if( templen && (fhdr->state == fhdrWAIT || fhdr->state == fhdrLF) ) {
- if( tempidx < templen ) {
- buf[n++] = tempbuf[tempidx++];
- continue;
- }
- tempidx = templen = 0;
+
+ len = 2; /* reserve 2 bytes for the length header */
+ size -= 2; /* and 2 for the term header */
+ while( !rc && len < size ) {
+ if( afx->helpidx < afx->helplen ) { /* flush the last buffer */
+ n = afx->helplen;
+ for(nn=afx->helpidx; len < size && nn < n ; nn++ )
+ buf[len++] = afx->helpbuf[nn];
+ afx->helpidx = nn;
+ continue;
}
+ if( state == fhdrEOF ) {
+ rc = -1;
+ continue;
+ }
+ /* read a new one */
+ n = DIM(afx->helpbuf);
+ afx->helpidx = 0;
+ state = find_header( state, afx->helpbuf, &n, a, 0 );
+ switch( state) {
+ case fhdrERROR:
+ case fhdrEOF:
+ rc = -1;
+ break;
- if( helpidx < helplen )
- c = helpbuf[helpidx++];
- else if( (c=iobuf_get(a)) == -1 )
+ case fhdrCLEARSIG:
+ case fhdrREADClearsig:
+ case fhdrREADClearsigNext:
+ afx->helplen = n;
break;
- if( find_header( fhdr, c ) ) {
- m_free(afx->fake);
- afx->fake = NULL;
- afx->inp_checked = 1;
- afx->crc = CRCINIT;
- afx->idx = 0;
- afx->radbuf[0] = 0;
- /* we don't need to care about the tempbuf */
+
+ case fhdrENDClearsig:
+ afx->helplen = n;
+ afx->faked = 0;
+ rc = -1;
break;
- }
- if( fhdr->state == fhdrWAIT || fhdr->state == fhdrLF ) {
- if( templen ) {
- tempidx = 0;
- continue;
- }
- buf[n++] = c;
- }
- else if( fhdr->state == fhdrWAITINFO
- || fhdr->state == fhdrINFO )
- ;
- else { /* store it in another temp. buf */
- assert( templen < DIM(afx->tempbuf) );
- tempbuf[templen++] = c;
+
+ default: BUG();
}
}
- buf[0] = (n-2) >> 8;
- buf[1] = (n-2);
- if( !afx->fake ) { /* write last (ending) length header */
- buf[n++] = 0;
- buf[n++] = 0;
+ buf[0] = (len-2) >> 8;
+ buf[1] = (len-2);
+ if( state == fhdrENDClearsig ) { /* write last (ending) length header */
+ buf[len++] = 0;
+ buf[len++] = 0;
+ rc = 0;
}
- afx->helpidx = helpidx;
- afx->helplen = helplen;
- afx->tempidx = tempidx;
- afx->templen = templen;
- *retn = n;
+ afx->parse_state = state;
+ *retn = len;
return rc;
}
@@ -493,11 +600,8 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
log_error("CRC error; %06lx - %06lx\n",
(ulong)afx->crc, (ulong)mycrc);
else {
- struct fhdr_struct fhdr;
-
- memset( &fhdr, 0, sizeof(fhdr) );
for(rc=0;!rc;) {
- rc = check_trailer( &fhdr, c );
+ rc = 0 /*check_trailer( &fhdr, c )*/;
if( !rc ) {
if( afx->helpidx < afx->helplen )
c = afx->helpbuf[afx->helpidx++];
@@ -561,13 +665,13 @@ armor_filter( void *opaque, int control,
return -1;
}
- if( afx->fake )
+ if( afx->faked )
rc = fake_packet( afx, a, &n, buf, size );
else if( !afx->inp_checked ) {
rc = check_input( afx, a );
if( afx->inp_bypass )
;
- else if( afx->fake ) {
+ else if( afx->faked ) {
/* the buffer is at least 20 bytes long, so it
* is easy to construct a packet */
buf[0] = 0xaf; /* old packet format, type 11, var length */