add "generic" format string based encoder and decoder (scan_asn1generic,

fmt_asn1generic, see t10.c for example usage)
add "generic" asn.1 dumper (in t10.c)
fix some read off-by-one errors, minor cleanups
add real OID support
add bitstring support
This commit is contained in:
leitner
2011-04-28 19:50:11 +00:00
parent e90320f819
commit e04ca78ff8
49 changed files with 483 additions and 110 deletions

View File

@@ -10,7 +10,9 @@ fmt_asn1int.o fmt_asn1string.o fmt_asn1transparent.o scan_asn1tag.o \
scan_asn1length.o scan_asn1int.o scan_asn1string.o scan_asn1INTEGER.o \
scan_asn1STRING.o scan_asn1SEQUENCE.o scan_asn1ENUMERATED.o \
scan_asn1BOOLEAN.o scan_asn1rawint.o scan_asn1SET.o fmt_asn1sint.o \
fmt_asn1sintpayload.o scan_asn1oid.o
fmt_asn1sintpayload.o scan_asn1oid.o scan_asn1BITSTRING.o \
scan_asn1tagint.o fmt_asn1tagint.o fmt_asn1OID.o scan_asn1generic.o \
fmt_asn1generic.o
ldap.a: scan_ldapmessage.o fmt_ldapmessage.o fmt_ldapbindrequest.o \
scan_ldapbindrequest.o scan_ldapbindresponse.o scan_ldapresult.o \
@@ -111,6 +113,7 @@ fmt_asn1sint.o: fmt_asn1sint.c asn1.h
fmt_asn1sintpayload.o: fmt_asn1sintpayload.c asn1.h
fmt_asn1string.o: fmt_asn1string.c asn1.h
fmt_asn1tag.o: fmt_asn1tag.c asn1.h
fmt_asn1tagint.o: fmt_asn1tagint.c asn1.h
fmt_asn1transparent.o: fmt_asn1transparent.c asn1.h
fmt_ldapadl.o: fmt_ldapadl.c asn1.h ldap.h
fmt_ldapava.o: fmt_ldapava.c asn1.h ldap.h
@@ -123,6 +126,8 @@ fmt_ldapsearchfilterstring.o: fmt_ldapsearchfilterstring.c ldap.h
fmt_ldapsearchrequest.o: fmt_ldapsearchrequest.c asn1.h ldap.h
fmt_ldapsearchresultentry.o: fmt_ldapsearchresultentry.c asn1.h ldap.h
fmt_ldapstring.o: fmt_ldapstring.c asn1.h ldap.h
fmt_asn1OID.o: fmt_asn1OID.c asn1.h
fmt_asn1generic.o: fmt_asn1generic.c asn1.h
scan_asn1BOOLEAN.o: scan_asn1BOOLEAN.c asn1.h
scan_asn1ENUMERATED.o: scan_asn1ENUMERATED.c asn1.h
@@ -130,12 +135,14 @@ scan_asn1INTEGER.o: scan_asn1INTEGER.c asn1.h
scan_asn1SEQUENCE.o: scan_asn1SEQUENCE.c asn1.h
scan_asn1SET.o: scan_asn1SET.c asn1.h
scan_asn1STRING.o: scan_asn1STRING.c asn1.h
scan_asn1BITSTRING.o: scan_asn1BITSTRING.c asn1.h
scan_asn1int.o: scan_asn1int.c asn1.h
scan_asn1length.o: scan_asn1length.c asn1.h
scan_asn1oid.o: scan_asn1oid.c asn1.h
scan_asn1rawint.o: scan_asn1rawint.c asn1.h
scan_asn1string.o: scan_asn1string.c asn1.h
scan_asn1tag.o: scan_asn1tag.c asn1.h
scan_asn1tagint.o: scan_asn1tagint.c asn1.h
scan_ldapaddrequest.o: scan_ldapaddrequest.c asn1.h ldap.h
scan_ldapava.o: scan_ldapava.c asn1.h ldap.h
scan_ldapbindrequest.o: scan_ldapbindrequest.c asn1.h ldap.h
@@ -148,5 +155,6 @@ scan_ldapsearchfilterstring.o: scan_ldapsearchfilterstring.c ldap.h
scan_ldapsearchrequest.o: scan_ldapsearchrequest.c asn1.h ldap.h
scan_ldapsearchresultentry.o: scan_ldapsearchresultentry.c asn1.h ldap.h
scan_ldapstring.o: scan_ldapstring.c asn1.h ldap.h
scan_asn1generic.o: scan_asn1generic.c asn1.h
ldap_match_sre.o: ldap_match_sre.c ldap.h

6
acl.c
View File

@@ -1,6 +1,7 @@
#define _FILE_OFFSET_BITS 64
#define MAIN
#include "ldap.h"
#include <buffer.h>
#include <stralloc.h>
#include <str.h>
@@ -11,7 +12,6 @@
#include <byte.h>
#include <mmap.h>
#include <case.h>
#include <ldap.h>
#include <uint16.h>
#include <uint32.h>
#include <open.h>
@@ -275,7 +275,7 @@ int marshalfilter(stralloc* x,struct assertion* a) {
int marshal(char* map,size_t filelen,const char* filename) {
size_t filters,acls,i,j,k;
size_t filter_offset,acl_offset;
size_t filter_offset; //,acl_offset;
struct acl* a;
uint32* F,* A;
uint32 attribute_count;
@@ -396,7 +396,7 @@ nomem:
A=malloc(sizeof(*A)*acls);
if (!A) goto nomem;
acl_offset=F[i]+(acls+1)*sizeof(*A);
// acl_offset=F[i]+(acls+1)*sizeof(*A);
i=0;
for (a=root; a; a=a->next) {

28
asn1.h
View File

@@ -1,3 +1,6 @@
#ifndef ASN1_H
#define ASN1_H
/* parser and formatter for ASN.1 DER encoding.
* The parser can read BER encoding, too. */
@@ -18,12 +21,18 @@ enum asn1_tagtype {
enum asn1_tag {
BOOLEAN=1,
INTEGER=2,
BIT_STRING=3,
OCTET_STRING=4,
OBJECT_IDENTIFIER=6,
ENUMERATED=10,
SEQUENCE_OF=16,
SET_OF=17,
UTCTIME=23
};
/* write variable length integer in the encoding used in tag and oid */
size_t fmt_asn1tagint(char* dest,unsigned long val);
/* write int in least amount of bytes, return number of bytes */
/* as used in ASN.1 tag */
size_t fmt_asn1tag(char* dest,enum asn1_tagclass tc,enum asn1_tagtype tt,
@@ -85,12 +94,17 @@ size_t fmt_asn1string(char* dest,enum asn1_tagclass tc,enum asn1_tagtype tt,
/* write ASN.1 SET */
#define fmt_asn1SET(dest,l) fmt_asn1transparent(dest,UNIVERSAL,CONSTRUCTED,SET_OF,l)
size_t fmt_asn1OID(char* dest,const unsigned long* array,unsigned long len);
/* conventions for the parser routines:
* src points to the first byte to parse
* max points to the first byte behind the buffer
* the return value is the number of bytes parsed or 0 for parse error */
/* parse ASN.1 variable length integer as used in tag and oid */
size_t scan_asn1tagint(const char* src,const char* max,unsigned long* val);
/* parse ASN.1 tag into a tag class, tag type and tag number */
size_t scan_asn1tag(const char* src,const char* max,
enum asn1_tagclass* tc,enum asn1_tagtype* tt, unsigned long* tag);
@@ -119,5 +133,19 @@ size_t scan_asn1BOOLEAN(const char* src,const char* max,unsigned long* l);
size_t scan_asn1INTEGER(const char* src,const char* max,signed long* l);
size_t scan_asn1ENUMERATED(const char* src,const char* max,unsigned long* l);
size_t scan_asn1STRING(const char* src,const char* max,const char** s,size_t* l);
size_t scan_asn1BITSTRING(const char* src,const char* max,const char** s,size_t* l);
size_t scan_asn1SEQUENCE(const char* src,const char* max,size_t* len);
size_t scan_asn1SET(const char* src,const char* max,size_t* len);
/* scan an ASN.1 OID and put the numbers into array.
* Return numbers of bytes parsed or 0 on error.
* Put at most arraylen longs into array; if the OID is longer, or if array is NULL, return real number in arraylen and return 0
* If 0 is returned and arraylen is also 0, there was a parse error */
size_t scan_asn1oid(const char* src,const char* max,unsigned long* array,unsigned long* arraylen);
struct string {
size_t l;
const char* s;
};
#endif

2
auth.c
View File

@@ -1,3 +1,4 @@
#define _XOPEN_SOURCE
#include <sys/types.h>
#ifdef __dietlibc__
#include <md5.h>
@@ -7,7 +8,6 @@
#define MD5Update MD5_Update
#define MD5Final MD5_Final
#endif
#define _XOPEN_SOURCE
#include <unistd.h>
#include <stdlib.h>
#include <alloca.h>

View File

@@ -15,7 +15,7 @@ int main(int argc,char* argv[]) {
if (!map) {
buffer_puts(buffer_2,"could not open `");
buffer_puts(buffer_2,fn);
buffer_puts(buffer_2,"´: ");
buffer_puts(buffer_2,"': ");
buffer_puterror(buffer_2);
buffer_putnlflush(buffer_2);
exit(1);

16
fmt_asn1OID.c Normal file
View File

@@ -0,0 +1,16 @@
#include "asn1.h"
size_t fmt_asn1OID(char* dest,const unsigned long* array,unsigned long len) {
size_t i,l,l2;
if (len<2) return 0;
for (l=1,i=2; i<len; ++i) {
l+=fmt_asn1tagint(dest,array[i]);
}
l2=fmt_asn1transparent(dest,UNIVERSAL,PRIMITIVE,OBJECT_IDENTIFIER,l);
if (!dest) return l+l2;
dest[l2]=array[0]*40+array[1];
dest+=l2+1;
for (i=2; i<len; ++i)
dest+=fmt_asn1tagint(dest,array[i]);
return l+l2;
}

76
fmt_asn1generic.c Normal file
View File

@@ -0,0 +1,76 @@
#include <stdarg.h>
#include <string.h>
#include "asn1.h"
size_t fmt_asn1generic(char* dest,const char* fmt,...) {
size_t containerstack[100];
size_t curinstack=0;
va_list args;
va_start(args,fmt);
unsigned long* application=0;
struct string* s;
struct string S;
size_t curlen=0;
size_t cursor=0;
size_t seqlen;
unsigned long appstore;
while (*fmt) {
char* realdest=dest?dest+cursor:NULL;
switch (*fmt) {
case 'a': // make next tag use APPLICATION with this tag
appstore=va_arg(args,unsigned long);
application=&appstore;
break;
case 'i': // send integer
{
unsigned long i=va_arg(args,unsigned long);
if (application)
curlen=fmt_asn1int(realdest,APPLICATION,PRIMITIVE,*application,i);
else
curlen=fmt_asn1int(realdest,UNIVERSAL,PRIMITIVE,INTEGER,i);
application=NULL;
break;
}
case 'S': // send OCTET_STRING, using struct string* as arg
s=va_arg(args,struct string*);
copystring:
if (application)
curlen=fmt_asn1string(realdest,APPLICATION,PRIMITIVE,*application,s->s,s->l);
else
curlen=fmt_asn1string(realdest,UNIVERSAL,PRIMITIVE,OCTET_STRING,s->s,s->l);
application=NULL;
break;
case 's': // send OCTET_STRING, using const char* with strlen() as arg
S.s=va_arg(args,const char*);
S.l=strlen(S.s);
s=&S;
goto copystring;
case '{': // start SEQUENCE
if (application)
curlen=fmt_asn1tag(realdest,APPLICATION,CONSTRUCTED,*application);
else
curlen=fmt_asn1tag(realdest,UNIVERSAL,CONSTRUCTED,SEQUENCE_OF);
containerstack[curinstack++]=cursor+curlen;
application=NULL;
break;
case '}': // end of SEQUENCE
/* we just wrote the tag and the sequence. Now that we wrote the
* sequence, we know the length it took, and we need to move the
* sequence data backwards to make room to write the ASN.1 length */
{
char* anfang;
if (!curinstack) return 0;
anfang=dest+containerstack[--curinstack];
seqlen=dest+cursor-anfang;
curlen=fmt_asn1length(NULL,seqlen);
if (!dest) break;
memmove(anfang+curlen,anfang,seqlen);
fmt_asn1length(anfang,seqlen);
break;
}
}
cursor+=curlen;
++fmt;
}
return cursor;
}

View File

@@ -4,22 +4,12 @@
/* as used in ASN.1 tags */
size_t fmt_asn1tag(char* dest,enum asn1_tagclass tc,enum asn1_tagtype tt,unsigned long l) {
/* encoding is either l%128 or (0x1f,...) */
size_t needed=((sizeof l)*7)/8,i;
if (l<0x1f) {
if (dest) *dest=(int)tc+(int)tt+(l&0x1f);
return 1;
}
for (i=1; i<needed; ++i)
if (!(l>>(i*7)))
break;
if (dest) {
size_t j=i;
*dest=(int)tc+(int)tt+0x1f; ++dest;
while (j) {
--j;
*dest=((l>>(j*7))&0x7f) + (j?0x80:0);
++dest;
}
}
return i+1;
return fmt_asn1tagint(dest,l)+1;
}

17
fmt_asn1tagint.c Normal file
View File

@@ -0,0 +1,17 @@
#include "asn1.h"
size_t fmt_asn1tagint(char* dest,unsigned long l) {
size_t needed=((sizeof l)*7)/8,i;
for (i=1; i<needed; ++i)
if (!(l>>(i*7)))
break;
if (dest) {
size_t j=i;
while (j) {
--j;
*dest=((l>>(j*7))&0x7f) + (j?0x80:0);
++dest;
}
}
return i;
}

View File

@@ -1,4 +1,3 @@
#include "asn1.h"
#include "ldap.h"
static size_t doit(char* dest,struct AttributeDescriptionList* adl,int seq) {

View File

@@ -1,4 +1,3 @@
#include "asn1.h"
#include "ldap.h"
size_t fmt_ldapava(char* dest,struct AttributeValueAssertion* a) {

View File

@@ -1,5 +1,4 @@
#include <string.h>
#include "asn1.h"
#include "ldap.h"
#include "str.h"
#include "rangecheck.h"

View File

@@ -1,4 +1,3 @@
#include "asn1.h"
#include "ldap.h"
size_t fmt_ldapmessage(char* dest,long messageid,long op,size_t len) {

View File

@@ -1,4 +1,3 @@
#include "asn1.h"
#include "ldap.h"
size_t fmt_ldappal(char* dest,struct PartialAttributeList* pal) {

View File

@@ -1,4 +1,3 @@
#include "asn1.h"
#include "ldap.h"
#include "str.h"

View File

@@ -1,5 +1,4 @@
#include <byte.h>
#include "asn1.h"
#include "ldap.h"
#include <stdlib.h>
@@ -51,7 +50,7 @@ size_t fmt_ldapsearchfilter(char* dest,struct Filter* f) {
}
break;
case PRESENT:
return fmt_asn1string(dest,PRIVATE,PRIMITIVE,f->type,f->ava.desc.s,f->ava.desc.l);
return fmt_asn1string(dest,PRIVATE,PRIMITIVE,(enum asn1_tag)f->type,f->ava.desc.s,f->ava.desc.l);
break;
default: return 0;
}

View File

@@ -1,4 +1,3 @@
#include "asn1.h"
#include "ldap.h"
size_t fmt_ldapsearchrequest(char* dest,struct SearchRequest* sr) {

View File

@@ -1,4 +1,3 @@
#include "asn1.h"
#include "ldap.h"
size_t fmt_ldapsearchresultentry(char* dest,struct SearchResultEntry* sre) {

View File

@@ -1,4 +1,3 @@
#include "asn1.h"
#include "ldap.h"
size_t fmt_ldapstring(char* dest,struct string* s) {

View File

@@ -1,5 +1,4 @@
#include <stdlib.h>
#include "asn1.h"
#include "ldap.h"
void free_ldapsearchfilter(struct Filter* f) {

6
ldap.h
View File

@@ -1,14 +1,10 @@
#ifndef _LDAP_H
#define _LDAP_H
#include "asn1.h"
#include <stddef.h>
#include <inttypes.h>
struct string {
size_t l;
const char* s;
};
int matchstring(struct string* s,const char* c);
int matchcasestring(struct string* s,const char* c);
int matchprefix(struct string* s,const char* c);

View File

@@ -1,4 +1,3 @@
#include "ldap.h"
#include "ldif.h"
#include "byte.h"
#include "str.h"

View File

@@ -4,7 +4,6 @@
#include <string.h>
#include "byte.h"
#include "buffer.h"
#include "asn1.h"
#include "ldap.h"
#include "socket.h"
#include "ip4.h"
@@ -51,7 +50,7 @@ static int ldapbind(int sock) {
}
int main(int argc,char* argv[]) {
int sock;
int sock=0;
char buf[BUFSIZE];
int len=0;
char* me;

View File

@@ -3,7 +3,6 @@
#include <string.h>
#include "byte.h"
#include "buffer.h"
#include "asn1.h"
#include "ldap.h"
#include "socket.h"
#include "ip4.h"

View File

@@ -4,7 +4,6 @@
#include <string.h>
#include "byte.h"
#include "buffer.h"
#include "asn1.h"
#include "ldap.h"
#include "socket.h"
#include "ip4.h"

3
ldif.h
View File

@@ -1,7 +1,8 @@
#define _FILE_OFFSET_BITS 64
#include <sys/stat.h>
#include <inttypes.h>
#include <ldap.h>
#include "asn1.h"
#include "ldap.h"
/* how many attributes do we allow per record? */
#define ATTRIBS 100

View File

@@ -144,7 +144,7 @@ int main(int argc,char* argv[]) {
char* destname=argc<3?"data":argv[2];
char* tempname;
unsigned long size_of_string_table,indices_offset;
long offset_stringtable;
// long offset_stringtable;
char* map;
uint32 attrofs,classofs;
@@ -301,7 +301,7 @@ writeerror:
uint32_pack(map+4*4,size_of_string_table); /* size_of_string_table */
// size_of_string_table=stringtable.used+classes.strings.used+attributes.strings.used;
offset_stringtable=5*4;
// offset_stringtable=5*4;
offset_classes=outofs;
munmap(map,5*4);

27
scan_asn1BITSTRING.c Normal file
View File

@@ -0,0 +1,27 @@
#include "asn1.h"
size_t scan_asn1BITSTRING(const char* src,const char* max,const char** s,size_t* l) {
size_t tmp;
unsigned long tag;
enum asn1_tagclass tc;
enum asn1_tagtype tt;
if ((tmp=scan_asn1string(src,max,&tc,&tt,&tag,s,l)))
if (tc==UNIVERSAL && tt==PRIMITIVE && tag==BIT_STRING) {
unsigned char lastbyte;
if (*l==0 || /* length must be at least 1 because for bit strings, the first octet contains the number of unused bits in the last octet */
(unsigned char)(**s)>7) /* the number of unused bits in the last octet must not be negative and can be at most 7 */
return 0;
/* these are DER checks */
/* can't have unused bits if the length is 0 */
if (*l==1 && **s)
return 0;
/* now check if the unused bits are 0 */
lastbyte=(*s)[*l+1];
if (lastbyte & (0xff >> (8-**s)))
return 0;
*l=*l*8-(unsigned char)(**s);
++*s;
return tmp;
}
return 0;
}

107
scan_asn1generic.c Normal file
View File

@@ -0,0 +1,107 @@
#include <stdarg.h>
#include "asn1.h"
size_t scan_asn1generic(const char* src,const char* max,const char* fmt,...) {
size_t curlen,seqlen;
const char* maxstack[100];
size_t curmax=0;
va_list args;
int optional=0;
unsigned long* application=NULL;
unsigned long tag;
enum asn1_tagclass tc;
enum asn1_tagtype tt;
const char* orig=src;
va_start(args,fmt);
maxstack[0]=max;
while (*fmt) {
switch (*fmt) {
case '?': // ? = rest is optional (until end of sequence)
optional=1;
break;
case 'i': // i = INTEGER
{
long* dest=va_arg(args,long*);
*dest=0;
curlen=scan_asn1int(src,maxstack[curmax],&tc,&tt,&tag,dest);
if (application) {
if (tc!=APPLICATION) return 0;
*application=tag;
} else {
if (tc!=UNIVERSAL || tt!=PRIMITIVE || tag!=INTEGER)
return 0;
}
if (!curlen) { if (optional) break; else return 0; }
src+=curlen;
application=0;
break;
}
case 's': // s = STRING
{
struct string* dest=va_arg(args,struct string*);
dest->l=0;
dest->s=0;
curlen=scan_asn1string(src,maxstack[curmax],&tc,&tt,&tag,&dest->s,&dest->l);
if (!curlen) { if (optional) break; else return 0; }
if (application) {
if (tc!=APPLICATION) return 0;
*application=tag;
} else {
if (tc!=UNIVERSAL || tt!=PRIMITIVE || tag!=OCTET_STRING)
return 0;
}
src+=curlen;
application=0;
break;
}
case 'a': // next tag class is APPLICATION instead of UNIVERSAL; write tag to unsigned long*
{
application=va_arg(args,unsigned long*);
break;
}
case '{': // { = SEQUENCE
{
curlen=scan_asn1tag(src,maxstack[curmax],&tc,&tt,&tag);
if (!curlen) { if (optional) break; else return 0; }
if (application) {
if (tc!=APPLICATION) return 0;
*application=tag;
} else {
if (tc!=UNIVERSAL || tt!=CONSTRUCTED || tag!=SEQUENCE_OF)
return 0;
}
src+=curlen;
curlen=scan_asn1length(src,maxstack[curmax],&seqlen);
if (!curlen) return 0;
if (curmax>99) return 0;
maxstack[++curmax]=src+curlen+seqlen;
src+=curlen;
application=0;
break;
}
case '!': // save current max-src into size_t
// useful for ldap, where you have an application sequence
// and the tag defines which encoding you have inside the
// sequence, so you can't put it in the format string.
// you still need to know the length so you can call this function
// again on the rest of the data.
{
size_t* dest=va_arg(args,size_t*);
*dest=maxstack[curmax]-src;
break;
}
case '}': // } = end of SEQUENCE
{
optional=0;
if (curmax==0) return 0;
--curmax;
break;
}
default:
return 0;
}
++fmt;
}
va_end(args);
return src-orig;
}

View File

@@ -3,7 +3,7 @@
size_t scan_asn1length(const char* src,const char* max,size_t* length) {
const char* orig=src;
if (src>max) return 0;
if (src>=max) return 0;
/* If the highest bit of the first byte is clear, the byte is the length.
* Otherwise the next n bytes are the length (n being the lower 7 bits) */
if (*src&0x80) {

View File

@@ -1,49 +1,49 @@
#include "asn1.h"
size_t scan_asn1oid(const char* src,const char* max) {
size_t res,tmp,tlen;
unsigned long tag;
size_t scan_asn1oid(const char* src,const char* max,unsigned long* array,unsigned long* arraylen) {
const char* orig=src;
size_t res,tlen,cur=0,al;
unsigned long tag,tmp;
enum asn1_tagclass tc;
enum asn1_tagtype tt;
if (!(res=scan_asn1tag(src,max,&tc,&tt,&tag))) goto error;
if (!(tmp=scan_asn1length(src+res,max,&tlen))) goto error;
if (!arraylen) return 0;
al=*arraylen; *arraylen=0;
if (!(res=scan_asn1tag(src,max,&tc,&tt,&tag))) return 0;
if (tc!=UNIVERSAL || tt!=PRIMITIVE || tag!=OBJECT_IDENTIFIER) return 0;
if (!(tmp=scan_asn1length(src+res,max,&tlen))) return 0;
if (tlen<1) return 0; /* there has to be at least one octet */
res+=tmp;
if (max>src+res+tlen) max=src+res+tlen; /* clamp max down */
src+=res;
{
size_t i,x,y;
tmp=0;
for(i=0;src[res+i]&128;++i)
tmp=(tmp<<7)+((unsigned char)src[res+i]&(~128));
tmp=(tmp<<7)+(unsigned char)src[res+i]; ++i;
x=tmp/40; y=tmp-x*40;
/* AFAIK gilt fuer alle bisher zugewiesenen OIDs: x<=2 & y<40 */
#if 1
/* Hier wird das Beispiel aus dem Standard korrekt geparst. */
while (x>2) { --x; y+=40; }
#else
/* Hier nicht. Dennoch arbeiten einige ASN.1 Parser ebenso. */
while (y>40) { y-=40; ++x; }
#endif
#if 0
buffer_putulong(buffer_2,x);
buffer_puts(buffer_2,".");
buffer_putulong(buffer_2,y);
#endif
for(;i<tlen;++i) {
tmp=0;
for(;src[res+i]&128;++i)
tmp=(tmp<<7)+((unsigned char)src[res+i]&(~128));
tmp=(tmp<<7)+(unsigned char)src[res+i];
#if 0
buffer_puts(buffer_2,".");
buffer_putulong(buffer_2,tmp);
#endif
int a,b;
a=(unsigned char)*src;
b=a%40;
a/=40;
/* a can be 0, 1 or 2. And b is <=39 if a is 0 or 1.
* So, if a is bigger than 2, it is really 2 */
if (a>2) {
b+=(a-2)*40;
a=2;
}
#if 0
buffer_putsflush(buffer_2,"\n");
#endif
if (array && cur<al) array[cur]=a; ++cur;
if (array && cur<al) array[cur]=b; ++cur;
}
return res+tlen;
error:
return 0;
for (++src; src<max; ) {
size_t i;
unsigned long tmp;
if (!(i=scan_asn1tagint(src,max,&tmp)))
return 0;
src+=i;
if (array && cur<al) array[cur]=tmp; ++cur;
}
/* if we got this far, then we have an OID, but it might not have fit */
*arraylen=cur;
if (cur>al) /* did not fit */
return 0;
return src-orig;
}

View File

@@ -3,6 +3,7 @@
size_t scan_asn1rawint(const char* src,const char* max,size_t len,long* l) {
size_t i,j;
long m;
if (src>=max) return 0;
if (*src<0) m=-1; else m=0;
for (i=j=0; i<len; ++i,++j) {
if ((m==0 && *src==0) || (m==-1 && *src==-1)) --j;

View File

@@ -1,24 +1,15 @@
#include "asn1.h"
size_t scan_asn1tag(const char* src,const char* max,enum asn1_tagclass* tc,enum asn1_tagtype* tt,unsigned long* tag) {
const char* orig=src;
if (max<=src) return 0;
*tc=(*src&0xC0);
*tt=(*src&0x20);
if (max<src) return 0;
/* The lower 5 bits are the tag, unless it's 0x1f, in which case the
* next bytes are the tag: always take the lower 7 bits; the last byte
* in the sequence is marked by a cleared high bit */
if ((*src & 0x1f) == 0x1f) {
unsigned long l=0;
for (;;) {
++src;
if (src>max) return 0;
if (l>(((unsigned long)-1)>>7)) return 0; /* catch integer overflow */
l=l*128+(*src&0x7F);
if (!(*src&0x80)) break;
}
*tag=l;
return (src-orig+1);
size_t res=scan_asn1tagint(src+1,max,tag);
return res+!!res; /* add 1 unless it's 0, then leave 0 */
} else {
*tag=*src&0x1f;
return 1;

14
scan_asn1tagint.c Normal file
View File

@@ -0,0 +1,14 @@
#include "asn1.h"
size_t scan_asn1tagint(const char* src,const char* max,unsigned long* val) {
const char* orig=src;
unsigned long l=0;
for (;; ++src) {
if (src>=max) return 0;
if (l>(((unsigned long)-1)>>7)) return 0; /* catch integer overflow */
l=l*128+(*src&0x7F);
if (!(*src&0x80)) break;
}
*val=l;
return src-orig+1;
}

View File

@@ -1,5 +1,4 @@
#include <stdlib.h>
#include "asn1.h"
#include "ldap.h"
#include "buffer.h"
#include "byte.h"

View File

@@ -1,4 +1,3 @@
#include "asn1.h"
#include "ldap.h"
size_t scan_ldapava(const char* src,const char* max,struct AttributeValueAssertion* ava) {

View File

@@ -1,4 +1,3 @@
#include "asn1.h"
#include "ldap.h"
size_t scan_ldapbindrequest(const char* src,const char* max,

View File

@@ -1,4 +1,3 @@
#include "asn1.h"
#include "ldap.h"
size_t scan_ldapbindresponse(const char* src,const char* max,

View File

@@ -1,4 +1,3 @@
#include "asn1.h"
#include "ldap.h"
size_t scan_ldapdeleterequest(const char* src,const char* max,

View File

@@ -1,4 +1,3 @@
#include "asn1.h"
#include "ldap.h"
size_t scan_ldapmessage(const char* src,const char* max,

View File

@@ -1,5 +1,4 @@
#include <stdlib.h>
#include "asn1.h"
#include "ldap.h"
#if 0

View File

@@ -1,4 +1,3 @@
#include "asn1.h"
#include "ldap.h"
size_t scan_ldapresult(const char* src,const char* max,unsigned long* result,

View File

@@ -1,4 +1,3 @@
#include "asn1.h"
#include "ldap.h"
#include <stdlib.h>
@@ -40,7 +39,7 @@ size_t scan_ldapsearchfilter(const char* src,const char* max,struct Filter** f)
if (tc!=PRIVATE || (tt!=CONSTRUCTED && tag!=7) || tag>9) goto error;
if (!(tmp=scan_asn1length(src+res,max,&len))) goto error;
res+=tmp;
if (src+res+len>max) goto error;
if (src+res+len>=max) goto error;
if (!(*f=malloc(sizeof(struct Filter)))) goto error;
(*f)->next=0;
(*f)->x=0;

View File

@@ -1,5 +1,4 @@
#include <stdlib.h>
#include "asn1.h"
#include "ldap.h"
size_t scan_ldapsearchrequest(const char* src,const char* max,

View File

@@ -1,5 +1,4 @@
#include <stdlib.h>
#include "asn1.h"
#include "ldap.h"
size_t scan_ldapsearchresultentry(const char* src,const char* max,struct SearchResultEntry* sre) {

View File

@@ -1,5 +1,4 @@
#include <asn1.h>
#include <ldap.h>
#include "ldap.h"
size_t scan_ldapstring(const char* src,const char* max,struct string* s) {
return scan_asn1STRING(src,max,&s->s,&s->l);

129
t10.c Normal file
View File

@@ -0,0 +1,129 @@
#include <stdio.h>
#include <byte.h>
#include "asn1.h"
void printasn1(const char* buf,const char* max) {
const char* maxstack[100];
size_t sptr=0;
size_t indent=0;
unsigned long tag;
enum asn1_tagclass tc;
enum asn1_tagtype tt;
size_t cl,len;
maxstack[sptr]=max;
while (buf<max) {
size_t i;
printf("%*s",indent,"");
cl=scan_asn1tag(buf,maxstack[sptr],&tc,&tt,&tag);
if (cl==0) {
printf("[could not parse tag]\n");
return;
}
printf("tag ");
switch (tc) {
case UNIVERSAL: printf("UNIVERSAL"); break;
case APPLICATION: printf("APPLICATION"); break;
case PRIVATE: printf("PRIVATE"); break;
case CONTEXT_SPECIFIC: printf("CONTEXT_SPECIFIC"); break;
default: printf("[illegal tag class 0x%x]\n",tc); return;
}
printf(" ");
switch (tt) {
case PRIMITIVE: printf("PRIMITIVE"); break;
case CONSTRUCTED: printf("CONSTRUCTED"); break;
default: printf("[illegal tag type 0x%x]\n",tt); return;
}
printf(" ");
if (tc!=UNIVERSAL)
printf("%d (0x%x)",tag,tag);
else switch (tag) {
case BOOLEAN: printf("BOOLEAN"); break;
case INTEGER: printf("INTEGER"); break;
case BIT_STRING: printf("BIT_STRING"); break;
case OCTET_STRING: printf("OCTET_STRING"); break;
case ENUMERATED: printf("ENUMERATED"); break;
case SEQUENCE_OF: printf("SEQUENCE_OF"); break;
case SET_OF: printf("SET_OF"); break;
case UTCTIME: printf("UTCTime"); break;
default: printf("[unsupported tag 0x%x]",tag); break;
}
buf+=cl;
cl=scan_asn1length(buf,maxstack[sptr],&len);
if (cl==0) {
puts("[could not parse length]");
return;
}
printf(" length %zu\n",len);
buf+=cl;
if (tc==UNIVERSAL && tt==PRIMITIVE) {
if (tag==INTEGER) {
unsigned long l;
size_t mlen;
mlen=scan_asn1rawint(buf,maxstack[sptr],cl,&l);
if (mlen)
printf("%*s-> %ld\n",indent,"",l);
} else if (tag==OCTET_STRING) {
printf("%*s-> \"",indent,"");
for (i=0; i<len; ++i) {
if (buf[i]<' ')
printf("\\x%02x",buf[i]);
else
putchar(buf[i]);
}
printf("\"\n");
}
}
if (tt==CONSTRUCTED) {
printf("%*s{\n",indent,"");
indent+=2;
if (sptr>=99) {
printf("too many nested constructed elements!\n");
return;
}
maxstack[++sptr]=buf+len;
} else
buf+=len;
while (sptr && maxstack[sptr]<=buf) {
--sptr;
indent-=2;
printf("%*s}\n",indent,"");
}
}
}
main() {
char buf[1024];
int l,i;
byte_zero(buf,1024);
l=fmt_asn1generic(buf,"a{is}",8,23,"fnord");
printf("formatted into %d bytes\n",l);
{
printf("-> ");
for (i=0; i<l; ++i)
printf("%02x ",(unsigned char)(buf[i]));
printf("\n");
}
printasn1(buf,buf+l);
{
unsigned long a;
unsigned long a2;
unsigned long b;
struct string c;
l=scan_asn1generic(buf,buf+l,"a{!is}",&a,&a2,&b,&c);
printf("%lu\n",l);
if (l) {
printf("got application tag %d (should be 8)\n",a);
printf("got sequence length %d\n",a2);
printf("got integer %d (should be 23)\n",b);
printf("got string \"%.*s\" (should be \"fnord\")\n",c.l,c.s);
}
}
}

1
t2.c
View File

@@ -2,7 +2,6 @@
#include <unistd.h>
#include <stdio.h>
#include "mmap.h"
#include "asn1.h"
#include "ldap.h"
#endif

View File

@@ -639,7 +639,7 @@ static void tagmatches(uint32* index,size_t elements,struct string* s,
setbit(b,rec);
/* there may be multiple matches.
* Look before and after mid, too */
if (mid) /* thx Andreas Stührk */
if (mid) /* thx Andreas Stührk */
for (k=mid-1; k>0; --k) {
m=uint32_read((char*)(&index[k]));
if ((ft==LESSEQUAL) || (l=match(s,map+m))==0) {