diff options
author | Dr. Stephen Henson <steve@openssl.org> | 2000-07-07 13:24:36 +0000 |
---|---|---|
committer | Dr. Stephen Henson <steve@openssl.org> | 2000-07-07 13:24:36 +0000 |
commit | a338e21bd1f1654b9fc90352a45e054be1f947eb (patch) | |
tree | 3b1b06a17133076ff9331dd6a03a9d49570de31a | |
parent | 5789f8f780c21696c92e8138ad51afc53fa0d56d (diff) | |
download | openssl-a338e21bd1f1654b9fc90352a45e054be1f947eb.tar.gz |
New ASN1 functions that just deal with
content octets, not tag+length.
-rw-r--r-- | CHANGES | 12 | ||||
-rw-r--r-- | crypto/asn1/a_bitstr.c | 62 | ||||
-rw-r--r-- | crypto/asn1/a_enum.c | 156 | ||||
-rw-r--r-- | crypto/asn1/a_int.c | 84 | ||||
-rw-r--r-- | crypto/asn1/asn1.h | 12 |
5 files changed, 147 insertions, 179 deletions
@@ -4,6 +4,18 @@ Changes between 0.9.5a and 0.9.6 [xx XXX 2000] + *) New ASN1 functions, i2c_* and c2i_* for INTEGER and BIT + STRING types. These convert content octets to and from the + underlying type. The actual tag and length octets are + already assumed to have been read in and checked. These + are needed because all other string types have virtually + identical handling apart from the tag. By having versions + of the ASN1 functions that just operate on content octets + IMPLICIT tagging can be handled properly. It also allows + the ASN1_ENUMERATED code to be cut down because ASN1_ENUMERATED + and ASN1_INTEGER are identical apart from the tag. + [Steve Henson] + *) Change the handling of OID objects as follows: - New object identifiers are inserted in objects.txt, following diff --git a/crypto/asn1/a_bitstr.c b/crypto/asn1/a_bitstr.c index f6cadc530a..35fe01d27e 100644 --- a/crypto/asn1/a_bitstr.c +++ b/crypto/asn1/a_bitstr.c @@ -70,13 +70,27 @@ int ASN1_BIT_STRING_set(ASN1_BIT_STRING *x, unsigned char *d, int len) { return M_ASN1_BIT_STRING_set(x, d, len); } int i2d_ASN1_BIT_STRING(ASN1_BIT_STRING *a, unsigned char **pp) +{ + int len, ret; + len = i2c_ASN1_BIT_STRING(a, NULL); + ret=ASN1_object_size(0,len,V_ASN1_BIT_STRING); + if(pp) { + ASN1_put_object(pp,0,ret,V_ASN1_BIT_STRING,V_ASN1_UNIVERSAL); + i2c_ASN1_BIT_STRING(a, pp); + } + return ret; +} + +int i2c_ASN1_BIT_STRING(ASN1_BIT_STRING *a, unsigned char **pp) { - int ret,j,r,bits,len; + int ret,j,bits,len; unsigned char *p,*d; if (a == NULL) return(0); len=a->length; + ret=1+len; + if (pp == NULL) return(ret); if (len > 0) { @@ -104,36 +118,27 @@ int i2d_ASN1_BIT_STRING(ASN1_BIT_STRING *a, unsigned char **pp) } else bits=0; - ret=1+len; - r=ASN1_object_size(0,ret,V_ASN1_BIT_STRING); - if (pp == NULL) return(r); p= *pp; - ASN1_put_object(&p,0,ret,V_ASN1_BIT_STRING,V_ASN1_UNIVERSAL); *(p++)=(unsigned char)bits; d=a->data; memcpy(p,d,len); p+=len; if (len > 0) p[-1]&=(0xff<<bits); *pp=p; - return(r); + return(ret); } + +/* Convert DER encoded ASN1 BIT_STRING to ASN1_BIT_STRING structure */ ASN1_BIT_STRING *d2i_ASN1_BIT_STRING(ASN1_BIT_STRING **a, unsigned char **pp, long length) - { - ASN1_BIT_STRING *ret=NULL; - unsigned char *p,*s; +{ + unsigned char *p; long len; - int inf,tag,xclass; int i; - - if ((a == NULL) || ((*a) == NULL)) - { - if ((ret=M_ASN1_BIT_STRING_new()) == NULL) return(NULL); - } - else - ret=(*a); + int inf,tag,xclass; + ASN1_BIT_STRING *ret; p= *pp; inf=ASN1_get_object(&p,&len,&tag,&xclass,length); @@ -149,7 +154,30 @@ ASN1_BIT_STRING *d2i_ASN1_BIT_STRING(ASN1_BIT_STRING **a, unsigned char **pp, goto err; } if (len < 1) { i=ASN1_R_STRING_TOO_SHORT; goto err; } + ret = c2i_ASN1_BIT_STRING(a, &p, len); + if(ret) *pp = p; + return ret; +err: + ASN1err(ASN1_F_D2I_ASN1_BIT_STRING,i); + return(NULL); + +} + +ASN1_BIT_STRING *c2i_ASN1_BIT_STRING(ASN1_BIT_STRING **a, unsigned char **pp, + long len) + { + ASN1_BIT_STRING *ret=NULL; + unsigned char *p,*s; + int i; + if ((a == NULL) || ((*a) == NULL)) + { + if ((ret=M_ASN1_BIT_STRING_new()) == NULL) return(NULL); + } + else + ret=(*a); + + p= *pp; i= *(p++); /* We do this to preserve the settings. If we modify * the settings, via the _set_bit function, we will recalculate diff --git a/crypto/asn1/a_enum.c b/crypto/asn1/a_enum.c index 572ba2e1b2..34b1a38c49 100644 --- a/crypto/asn1/a_enum.c +++ b/crypto/asn1/a_enum.c @@ -71,88 +71,27 @@ ASN1_ENUMERATED *ASN1_ENUMERATED_new(void) void ASN1_ENUMERATED_free(ASN1_ENUMERATED *x) { M_ASN1_ENUMERATED_free(x); } -int i2d_ASN1_ENUMERATED(ASN1_ENUMERATED *a, unsigned char **pp) - { - int pad=0,ret,r,i,t; - unsigned char *p,*n,pb=0; - - if ((a == NULL) || (a->data == NULL)) return(0); - t=a->type; - if (a->length == 0) - ret=1; - else - { - ret=a->length; - i=a->data[0]; - if ((t == V_ASN1_ENUMERATED) && (i > 127)) { - pad=1; - pb=0; - } else if(t == V_ASN1_NEG_ENUMERATED) { - if(i>128) { - pad=1; - pb=0xFF; - } else if(i == 128) { - for(i = 1; i < a->length; i++) if(a->data[i]) { - pad=1; - pb=0xFF; - break; - } - } - } - ret+=pad; - } - r=ASN1_object_size(0,ret,V_ASN1_ENUMERATED); - if (pp == NULL) return(r); - p= *pp; - - ASN1_put_object(&p,0,ret,V_ASN1_ENUMERATED,V_ASN1_UNIVERSAL); - if (pad) *(p++)=pb; - if (a->length == 0) - *(p++)=0; - else if (t == V_ASN1_ENUMERATED) - { - memcpy(p,a->data,(unsigned int)a->length); - p+=a->length; - } - else { - /* Begin at the end of the encoding */ - n=a->data + a->length - 1; - p += a->length - 1; - i = a->length; - /* Copy zeros to destination as long as source is zero */ - while(!*n) { - *(p--) = 0; - n--; - i--; - } - /* Complement and increment next octet */ - *(p--) = ((*(n--)) ^ 0xff) + 1; - i--; - /* Complement any octets left */ - for(;i > 0; i--) *(p--) = *(n--) ^ 0xff; - p += a->length; - } - *pp=p; - return(r); +int i2d_ASN1_ENUMERATED(ASN1_ENUMERATED *a, unsigned char **pp) +{ + int len, ret; + len = i2c_ASN1_INTEGER(a, NULL); + ret=ASN1_object_size(0,len,V_ASN1_ENUMERATED); + if(pp) { + ASN1_put_object(pp,0,ret,V_ASN1_ENUMERATED,V_ASN1_UNIVERSAL); + i2c_ASN1_INTEGER(a, pp); } + return ret; +} ASN1_ENUMERATED *d2i_ASN1_ENUMERATED(ASN1_ENUMERATED **a, unsigned char **pp, long length) - { - ASN1_ENUMERATED *ret=NULL; - unsigned char *p,*to,*s; +{ + unsigned char *p; long len; - int inf,tag,xclass; int i; - - if ((a == NULL) || ((*a) == NULL)) - { - if ((ret=M_ASN1_ENUMERATED_new()) == NULL) return(NULL); - ret->type=V_ASN1_ENUMERATED; - } - else - ret=(*a); + int inf,tag,xclass; + ASN1_ENUMERATED *ret; p= *pp; inf=ASN1_get_object(&p,&len,&tag,&xclass,length); @@ -167,70 +106,17 @@ ASN1_ENUMERATED *d2i_ASN1_ENUMERATED(ASN1_ENUMERATED **a, unsigned char **pp, i=ASN1_R_EXPECTING_AN_ENUMERATED; goto err; } - - /* We must OPENSSL_malloc stuff, even for 0 bytes otherwise it - * signifies a missing NULL parameter. */ - s=(unsigned char *)OPENSSL_malloc((int)len+1); - if (s == NULL) - { - i=ERR_R_MALLOC_FAILURE; - goto err; - } - to=s; - if(!len) { - /* Strictly speaking this is an illegal ENUMERATED but we - * tolerate it. - */ - ret->type=V_ASN1_ENUMERATED; - } else if (*p & 0x80) /* a negative number */ - { - ret->type=V_ASN1_NEG_ENUMERATED; - if ((*p == 0xff) && (len != 1)) { - p++; - len--; - } - i = len; - p += i - 1; - to += i - 1; - while((!*p) && i) { - *(to--) = 0; - i--; - p--; - } - if(!i) { - *s = 1; - s[len] = 0; - p += len; - len++; - } else { - *(to--) = (*(p--) ^ 0xff) + 1; - i--; - for(;i > 0; i--) *(to--) = *(p--) ^ 0xff; - p += len; - } - } else { - ret->type=V_ASN1_ENUMERATED; - if ((*p == 0) && (len != 1)) - { - p++; - len--; - } - memcpy(s,p,(int)len); - p+=len; + ret = c2i_ASN1_INTEGER(a, &p, len); + if(ret) { + ret->type = (V_ASN1_NEG & ret->type) | V_ASN1_ENUMERATED; + *pp = p; } - - if (ret->data != NULL) OPENSSL_free(ret->data); - ret->data=s; - ret->length=(int)len; - if (a != NULL) (*a)=ret; - *pp=p; - return(ret); + return ret; err: ASN1err(ASN1_F_D2I_ASN1_ENUMERATED,i); - if ((ret != NULL) && ((a == NULL) || (*a != ret))) - M_ASN1_ENUMERATED_free(ret); return(NULL); - } + +} int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v) { diff --git a/crypto/asn1/a_int.c b/crypto/asn1/a_int.c index 82db75f5e1..721592bf1c 100644 --- a/crypto/asn1/a_int.c +++ b/crypto/asn1/a_int.c @@ -72,8 +72,22 @@ ASN1_INTEGER *ASN1_INTEGER_dup(ASN1_INTEGER *x) int ASN1_INTEGER_cmp(ASN1_INTEGER *x, ASN1_INTEGER *y) { return M_ASN1_INTEGER_cmp(x,y);} +/* Output ASN1 INTEGER including tag+length */ + +int i2d_ASN1_INTEGER(ASN1_INTEGER *a, unsigned char **pp) +{ + int len, ret; + len = i2c_ASN1_INTEGER(a, NULL); + ret=ASN1_object_size(0,len,V_ASN1_INTEGER); + if(pp) { + ASN1_put_object(pp,0,ret,V_ASN1_INTEGER,V_ASN1_UNIVERSAL); + i2c_ASN1_INTEGER(a, pp); + } + return ret; +} + /* - * This converts an ASN1 INTEGER into its DER encoding. + * This converts an ASN1 INTEGER into its content encoding. * The internal representation is an ASN1_STRING whose data is a big endian * representation of the value, ignoring the sign. The sign is determined by * the type: V_ASN1_INTEGER for positive and V_ASN1_NEG_INTEGER for negative. @@ -97,23 +111,23 @@ int ASN1_INTEGER_cmp(ASN1_INTEGER *x, ASN1_INTEGER *y) * followed by optional zeros isn't padded. */ -int i2d_ASN1_INTEGER(ASN1_INTEGER *a, unsigned char **pp) +int i2c_ASN1_INTEGER(ASN1_INTEGER *a, unsigned char **pp) { - int pad=0,ret,r,i,t; + int pad=0,ret,i,neg; unsigned char *p,*n,pb=0; if ((a == NULL) || (a->data == NULL)) return(0); - t=a->type; + neg=a->type & V_ASN1_NEG; if (a->length == 0) ret=1; else { ret=a->length; i=a->data[0]; - if ((t == V_ASN1_INTEGER) && (i > 127)) { + if (!neg && (i > 127)) { pad=1; pb=0; - } else if(t == V_ASN1_NEG_INTEGER) { + } else if(neg) { if(i>128) { pad=1; pb=0xFF; @@ -131,14 +145,12 @@ int i2d_ASN1_INTEGER(ASN1_INTEGER *a, unsigned char **pp) } ret+=pad; } - r=ASN1_object_size(0,ret,V_ASN1_INTEGER); - if (pp == NULL) return(r); + if (pp == NULL) return(ret); p= *pp; - ASN1_put_object(&p,0,ret,V_ASN1_INTEGER,V_ASN1_UNIVERSAL); if (pad) *(p++)=pb; if (a->length == 0) *(p++)=0; - else if (t == V_ASN1_INTEGER) memcpy(p,a->data,(unsigned int)a->length); + else if (!neg) memcpy(p,a->data,(unsigned int)a->length); else { /* Begin at the end of the encoding */ n=a->data + a->length - 1; @@ -157,30 +169,22 @@ int i2d_ASN1_INTEGER(ASN1_INTEGER *a, unsigned char **pp) for(;i > 0; i--) *(p--) = *(n--) ^ 0xff; } - *pp+=r; - return(r); + *pp+=ret; + return(ret); } +/* Convert DER encoded ASN1 INTEGER to ASN1_INTEGER structure */ ASN1_INTEGER *d2i_ASN1_INTEGER(ASN1_INTEGER **a, unsigned char **pp, long length) - { - ASN1_INTEGER *ret=NULL; - unsigned char *p,*to,*s, *pend; +{ + unsigned char *p; long len; - int inf,tag,xclass; int i; - - if ((a == NULL) || ((*a) == NULL)) - { - if ((ret=M_ASN1_INTEGER_new()) == NULL) return(NULL); - ret->type=V_ASN1_INTEGER; - } - else - ret=(*a); + int inf,tag,xclass; + ASN1_INTEGER *ret; p= *pp; inf=ASN1_get_object(&p,&len,&tag,&xclass,length); - pend = p + len; if (inf & 0x80) { i=ASN1_R_BAD_OBJECT_HEADER; @@ -192,6 +196,35 @@ ASN1_INTEGER *d2i_ASN1_INTEGER(ASN1_INTEGER **a, unsigned char **pp, i=ASN1_R_EXPECTING_AN_INTEGER; goto err; } + ret = c2i_ASN1_INTEGER(a, &p, len); + if(ret) *pp = p; + return ret; +err: + ASN1err(ASN1_F_D2I_ASN1_INTEGER,i); + return(NULL); + +} + + +/* Convert just ASN1 INTEGER content octets to ASN1_INTEGER structure */ + +ASN1_INTEGER *c2i_ASN1_INTEGER(ASN1_INTEGER **a, unsigned char **pp, + long len) + { + ASN1_INTEGER *ret=NULL; + unsigned char *p,*to,*s, *pend; + int i; + + if ((a == NULL) || ((*a) == NULL)) + { + if ((ret=M_ASN1_INTEGER_new()) == NULL) return(NULL); + ret->type=V_ASN1_INTEGER; + } + else + ret=(*a); + + p= *pp; + pend = p + len; /* We must OPENSSL_malloc stuff, even for 0 bytes otherwise it * signifies a missing NULL parameter. */ @@ -261,6 +294,7 @@ err: return(NULL); } + /* This is a version of d2i_ASN1_INTEGER that ignores the sign bit of * ASN1 integers: some broken software can encode a positive INTEGER * with its MSB set as negative (it doesn't add a padding zero). diff --git a/crypto/asn1/asn1.h b/crypto/asn1/asn1.h index be3317c896..fcce0f6925 100644 --- a/crypto/asn1/asn1.h +++ b/crypto/asn1/asn1.h @@ -86,11 +86,13 @@ extern "C" { #define V_ASN1_APP_CHOOSE -2 /* let the recipient choose */ +#define V_ASN1_NEG 0x100 /* negative flag */ + #define V_ASN1_UNDEF -1 #define V_ASN1_EOC 0 #define V_ASN1_BOOLEAN 1 /**/ #define V_ASN1_INTEGER 2 -#define V_ASN1_NEG_INTEGER (2+0x100) +#define V_ASN1_NEG_INTEGER (2 | V_ASN1_NEG) #define V_ASN1_BIT_STRING 3 #define V_ASN1_OCTET_STRING 4 #define V_ASN1_NULL 5 @@ -99,7 +101,7 @@ extern "C" { #define V_ASN1_EXTERNAL 8 #define V_ASN1_REAL 9 #define V_ASN1_ENUMERATED 10 -#define V_ASN1_NEG_ENUMERATED (10+0x100) +#define V_ASN1_NEG_ENUMERATED (10 | V_ASN1_NEG) #define V_ASN1_UTF8STRING 12 #define V_ASN1_SEQUENCE 16 #define V_ASN1_SET 17 @@ -526,8 +528,11 @@ unsigned char * ASN1_STRING_data(ASN1_STRING *x); ASN1_BIT_STRING * ASN1_BIT_STRING_new(void); void ASN1_BIT_STRING_free(ASN1_BIT_STRING *a); int i2d_ASN1_BIT_STRING(ASN1_BIT_STRING *a,unsigned char **pp); +int i2c_ASN1_BIT_STRING(ASN1_BIT_STRING *a,unsigned char **pp); ASN1_BIT_STRING *d2i_ASN1_BIT_STRING(ASN1_BIT_STRING **a,unsigned char **pp, long length); +ASN1_BIT_STRING *c2i_ASN1_BIT_STRING(ASN1_BIT_STRING **a,unsigned char **pp, + long length); int ASN1_BIT_STRING_set(ASN1_BIT_STRING *a, unsigned char *d, int length ); int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *a, int n, int value); @@ -547,8 +552,11 @@ int d2i_ASN1_BOOLEAN(int *a,unsigned char **pp,long length); ASN1_INTEGER * ASN1_INTEGER_new(void); void ASN1_INTEGER_free(ASN1_INTEGER *a); int i2d_ASN1_INTEGER(ASN1_INTEGER *a,unsigned char **pp); +int i2c_ASN1_INTEGER(ASN1_INTEGER *a,unsigned char **pp); ASN1_INTEGER *d2i_ASN1_INTEGER(ASN1_INTEGER **a,unsigned char **pp, long length); +ASN1_INTEGER *c2i_ASN1_INTEGER(ASN1_INTEGER **a,unsigned char **pp, + long length); ASN1_INTEGER *d2i_ASN1_UINTEGER(ASN1_INTEGER **a,unsigned char **pp, long length); ASN1_INTEGER * ASN1_INTEGER_dup(ASN1_INTEGER *x); |