1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-06-06 23:17:47 +02:00

Rewritten

This commit is contained in:
Werner Koch 1998-01-27 12:32:28 +00:00
parent b113394658
commit 57caafa433

View File

@ -49,24 +49,29 @@ static byte bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
static byte asctobin[256]; /* runtime initialized */ static byte asctobin[256]; /* runtime initialized */
static int is_initialized; static int is_initialized;
typedef enum {
fhdrINIT=0,
fhdrLF,
fhdrWAIT,
fhdrWAITINFO,
fhdrWAITCLEARSIG,
fhdrDASH,
fhdrHEAD,
fhdrDASH2,
fhdrINFO
} fhdr_state_t;
struct fhdr_struct { typedef enum {
fhdr_state_t state; fhdrHASArmor,
int count; fhdrNOArmor,
int hdr_line; /* number of the header line */ fhdrINIT,
char buf[256]; fhdrINITCont,
}; fhdrINITSkip,
fhdrCHECKBegin,
fhdrWAITHeader,
fhdrWAITClearsig,
fhdrSKIPHeader,
fhdrCLEARSIG,
fhdrREADClearsig,
fhdrEMPTYClearsig,
fhdrCHECKClearsig,
fhdrCHECKClearsig2,
fhdrREADClearsigNext,
fhdrENDClearsig,
fhdrTEXT,
fhdrERROR,
fhdrERRORShow,
fhdrEOF
} fhdr_state_t;
/* if we encounter this armor string with this index, go /* if we encounter this armor string with this index, go
@ -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 static void
initialize(void) initialize(void)
{ {
@ -124,18 +133,14 @@ initialize(void)
* Returns: True if it seems to be armored * Returns: True if it seems to be armored
*/ */
static int static int
is_armored( byte *buf, size_t len ) is_armored( byte *buf )
{ {
int ctb, pkttype; int ctb, pkttype;
if( len < 28 )
return 0; /* not even enough space for the "---BEGIN"... */
ctb = *buf; ctb = *buf;
if( !(ctb & 0x80) ) if( !(ctb & 0x80) )
return 1; /* invalid packet: assume it is armored */ return 1; /* invalid packet: assume it is armored */
pkttype = ctb & 0x40 ? (ctb & 0x3f) : ((ctb>>2)&0xf); pkttype = ctb & 0x40 ? (ctb & 0x3f) : ((ctb>>2)&0xf);
/*lenbytes = (ctb & 0x40) || ((ctb&3)==3)? 0 : (1<<(ctb & 3));*/
switch( pkttype ) { switch( pkttype ) {
case PKT_PUBLIC_CERT: case PKT_PUBLIC_CERT:
case PKT_SECRET_CERT: case PKT_SECRET_CERT:
@ -152,120 +157,246 @@ is_armored( byte *buf, size_t len )
} }
/****************
* parse an ascii armor.
static int * Returns: the state,
find_header( struct fhdr_struct *fhdr, int c ) * 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; const char *s;
char *p;
size_t buflen;
int cont;
int clearsig=0;
int hdr_line=0;
if( c == '\n' ) { buflen = *r_buflen;
switch( fhdr->state ) { assert(buflen >= 100 );
case fhdrINFO: buflen--;
if( !fhdr->count )
return 1; /* blank line: data starts with the next line */ do {
fhdr->buf[fhdr->count] = 0; switch( state ) {
log_debug("armor line: '%s'\n", fhdr->buf ); case fhdrHASArmor:
/* fall through */ /* read 28 bytes, which is the bare minimum for a BEGIN...
case fhdrWAITINFO: * and check wether this has a Armor. */
fhdr->state = fhdrINFO; c = 0;
fhdr->count = 0; for(n=0; n < 28 && (c=iobuf_get(a)) != -1 && c != '\n'; )
break; buf[n++] = c;
case fhdrWAITCLEARSIG: if( n < 28 || c == -1 )
if( fhdr->count++ == 1 ) /* skip the empty line */ state = fhdrNOArmor; /* too short */
return 1; /* clear signed text follows */ else if( !is_armored( buf ) )
else if( fhdr->count > 1 ) state = fhdrNOArmor;
fhdr->state = fhdrWAIT; /* was not valid */
break;
default:
fhdr->state = fhdrLF;
break;
}
}
else {
switch( fhdr->state ) {
case fhdrINIT:
case fhdrLF:
if( c == '-' ) {
fhdr->state = fhdrDASH;
fhdr->count = 1;
}
else else
fhdr->state = fhdrWAIT; state = fhdrINITCont;
break; break;
case fhdrWAIT:
case fhdrWAITINFO: case fhdrINIT: /* read some stuff into buffer */
case fhdrWAITCLEARSIG: 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; break;
case fhdrDASH:
if( c == '-' ) { case fhdrINITSkip:
if( ++fhdr->count == 5 ) { while( (c=iobuf_get(a)) != -1 && c != '\n' )
fhdr->state = fhdrHEAD; ;
fhdr->count = 0; state = c == -1? fhdrEOF : fhdrINIT;
break;
case fhdrSKIPHeader:
while( (c=iobuf_get(a)) != -1 && c != '\n' )
;
state = c == -1? fhdrEOF : fhdrWAITHeader;
break;
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 else
fhdr->state = fhdrWAIT; state = fhdrEOF;
break; break;
case fhdrHEAD:
if( c != '-' ) { case fhdrWAITClearsig: /* skip all empty lines (for clearsig) */
if( fhdr->count < DIM(fhdr->buf)-1 ) c = 0;
fhdr->buf[fhdr->count++] = c; 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 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
state = fhdrCHECKClearsig;
break;
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 { else {
fhdr->buf[fhdr->count] = 0; state = state == fhdrCHECKClearsig2 ?
for(i=0; (s=head_strings[i]); i++ ) fhdrREADClearsig : fhdrREADClearsigNext;
if( !strcmp(s,fhdr->buf) ) /* FIXME: add the lf to the buffer */
break;
if( s ) { /* found string; wait for trailing dashes */
fhdr->hdr_line = i;
fhdr->state = fhdrDASH2;
fhdr->count = 1;
}
else
fhdr->state = fhdrWAIT;
} }
break; break;
case fhdrDASH2: case fhdrREADClearsigNext:
if( c == '-' ) { /* Read to the end of the line, do not care about checking
if( ++fhdr->count == 5 ) { * for dashed escaped text of headers */
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;
break; break;
case fhdrINFO: case fhdrERRORShow:
if( fhdr->count < DIM(fhdr->buf)-1 ) log_debug("invalid clear text header: ");
fhdr->buf[fhdr->count++] = c; print_string( stderr, buf, n );
putc('\n', stderr);
state = fhdrERROR;
break; break;
default: abort(); default: BUG();
} }
} switch( state ) {
return 0; 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 );
/**************** if( clearsig && state == fhdrTEXT )
* check wether the trailer is okay. state = fhdrCLEARSIG;
* Returns: 0 := still in trailer *r_buflen = n;
* -1 := Okay return state;
* 1 := Error in trailer
*/
static int
check_trailer( struct fhdr_struct *fhdr, int c )
{
return -1;
/* FIXME: implement this ! */
} }
@ -274,59 +405,45 @@ static int
check_input( armor_filter_context_t *afx, IOBUF a ) check_input( armor_filter_context_t *afx, IOBUF a )
{ {
int rc = 0; int rc = 0;
int c; size_t n;
size_t n = 0, nn=0; fhdr_state_t state = afx->parse_state;
struct fhdr_struct fhdr;
assert( DIM(afx->helpbuf) >= 50 ); if( state != fhdrENDClearsig )
memset( &fhdr, 0, sizeof(fhdr) ); state = fhdrHASArmor;
/* read a couple of bytes */ n = DIM(afx->helpbuf);
for( n=0; n < DIM(afx->helpbuf); n++ ) { state = find_header( state, afx->helpbuf, &n, a, afx->helplen );
if( (c=iobuf_get(a)) == -1 ) switch( state ) {
break; case fhdrNOArmor:
afx->helpbuf[n] = c & 0xff;
}
if( !n )
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 {
afx->inp_checked = 1; afx->inp_checked = 1;
afx->inp_bypass = 1; afx->inp_bypass = 1;
afx->helplen = n;
break;
case fhdrERROR:
case fhdrEOF:
rc = -1;
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->crc = CRCINIT;
afx->idx = 0;
afx->radbuf[0] = 0;
break;
default: BUG();
} }
afx->parse_state = state;
return rc; return rc;
} }
@ -338,71 +455,61 @@ fake_packet( armor_filter_context_t *afx, IOBUF a,
size_t *retn, byte *buf, size_t size ) size_t *retn, byte *buf, size_t size )
{ {
int rc = 0; int rc = 0;
int c; size_t len = 0;
size_t n = 0; size_t n, nn;
struct fhdr_struct *fhdr = afx->fake; fhdr_state_t state = afx->parse_state;
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 = 100; /* FIXME: only used for testing (remove it) */ 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;
}
if( helpidx < helplen ) len = 2; /* reserve 2 bytes for the length header */
c = helpbuf[helpidx++]; size -= 2; /* and 2 for the term header */
else if( (c=iobuf_get(a)) == -1 ) while( !rc && len < size ) {
break; if( afx->helpidx < afx->helplen ) { /* flush the last buffer */
if( find_header( fhdr, c ) ) { n = afx->helplen;
m_free(afx->fake); for(nn=afx->helpidx; len < size && nn < n ; nn++ )
afx->fake = NULL; buf[len++] = afx->helpbuf[nn];
afx->inp_checked = 1; afx->helpidx = nn;
afx->crc = CRCINIT; continue;
afx->idx = 0;
afx->radbuf[0] = 0;
/* we don't need to care about the tempbuf */
break;
} }
if( fhdr->state == fhdrWAIT || fhdr->state == fhdrLF ) { if( state == fhdrEOF ) {
if( templen ) { rc = -1;
tempidx = 0; continue;
continue;
}
buf[n++] = c;
} }
else if( fhdr->state == fhdrWAITINFO /* read a new one */
|| fhdr->state == fhdrINFO ) n = DIM(afx->helpbuf);
; afx->helpidx = 0;
else { /* store it in another temp. buf */ state = find_header( state, afx->helpbuf, &n, a, 0 );
assert( templen < DIM(afx->tempbuf) ); switch( state) {
tempbuf[templen++] = c; case fhdrERROR:
case fhdrEOF:
rc = -1;
break;
case fhdrCLEARSIG:
case fhdrREADClearsig:
case fhdrREADClearsigNext:
afx->helplen = n;
break;
case fhdrENDClearsig:
afx->helplen = n;
afx->faked = 0;
rc = -1;
break;
default: BUG();
} }
} }
buf[0] = (n-2) >> 8; buf[0] = (len-2) >> 8;
buf[1] = (n-2); buf[1] = (len-2);
if( !afx->fake ) { /* write last (ending) length header */ if( state == fhdrENDClearsig ) { /* write last (ending) length header */
buf[n++] = 0; buf[len++] = 0;
buf[n++] = 0; buf[len++] = 0;
rc = 0;
} }
afx->helpidx = helpidx; afx->parse_state = state;
afx->helplen = helplen; *retn = len;
afx->tempidx = tempidx;
afx->templen = templen;
*retn = n;
return rc; 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", log_error("CRC error; %06lx - %06lx\n",
(ulong)afx->crc, (ulong)mycrc); (ulong)afx->crc, (ulong)mycrc);
else { else {
struct fhdr_struct fhdr;
memset( &fhdr, 0, sizeof(fhdr) );
for(rc=0;!rc;) { for(rc=0;!rc;) {
rc = check_trailer( &fhdr, c ); rc = 0 /*check_trailer( &fhdr, c )*/;
if( !rc ) { if( !rc ) {
if( afx->helpidx < afx->helplen ) if( afx->helpidx < afx->helplen )
c = afx->helpbuf[afx->helpidx++]; c = afx->helpbuf[afx->helpidx++];
@ -561,13 +665,13 @@ armor_filter( void *opaque, int control,
return -1; return -1;
} }
if( afx->fake ) if( afx->faked )
rc = fake_packet( afx, a, &n, buf, size ); rc = fake_packet( afx, a, &n, buf, size );
else if( !afx->inp_checked ) { else if( !afx->inp_checked ) {
rc = check_input( afx, a ); rc = check_input( afx, a );
if( afx->inp_bypass ) if( afx->inp_bypass )
; ;
else if( afx->fake ) { else if( afx->faked ) {
/* the buffer is at least 20 bytes long, so it /* the buffer is at least 20 bytes long, so it
* is easy to construct a packet */ * is easy to construct a packet */
buf[0] = 0xaf; /* old packet format, type 11, var length */ buf[0] = 0xaf; /* old packet format, type 11, var length */