New ASN1 functions that just deal with
authorDr. Stephen Henson <steve@openssl.org>
Fri, 7 Jul 2000 13:24:36 +0000 (13:24 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Fri, 7 Jul 2000 13:24:36 +0000 (13:24 +0000)
content octets, not tag+length.

CHANGES
crypto/asn1/a_bitstr.c
crypto/asn1/a_enum.c
crypto/asn1/a_int.c
crypto/asn1/asn1.h

diff --git a/CHANGES b/CHANGES
index b2afb86..f3a7021 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -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
index f6cadc5..35fe01d 100644 (file)
@@ -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
index 572ba2e..34b1a38 100644 (file)
@@ -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)
        {
index 82db75f..721592b 100644 (file)
@@ -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).
index be3317c..fcce0f6 100644 (file)
@@ -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);