Add OAEP.
[openssl.git] / crypto / asn1 / a_bitstr.c
index 2c101206511d88686fcdcda0abea4b6277f068d9..275de43eb6c1e27d1e9fec379e6ce979f702e7c8 100644 (file)
@@ -68,27 +68,50 @@ int i2d_ASN1_BIT_STRING(a,pp)
 ASN1_BIT_STRING *a;
 unsigned char **pp;
        {
-       int ret,j,r,bits;
+       int ret,j,r,bits,len;
        unsigned char *p,*d;
 
        if (a == NULL) return(0);
 
-       /* our bit strings are always a multiple of 8 :-) */
-       bits=0;
-       ret=1+a->length;
+       len=a->length;
+
+       if (len > 0)
+               {
+               if (a->flags & ASN1_STRING_FLAG_BITS_LEFT)
+                       {
+                       bits=(int)a->flags&0x07;
+                       }
+               else
+                       {
+                       for ( ; len > 0; len--)
+                               {
+                               if (a->data[len-1]) break;
+                               }
+                       j=a->data[len-1];
+                       if      (j & 0x01) bits=0;
+                       else if (j & 0x02) bits=1;
+                       else if (j & 0x04) bits=2;
+                       else if (j & 0x08) bits=3;
+                       else if (j & 0x10) bits=4;
+                       else if (j & 0x20) bits=5;
+                       else if (j & 0x40) bits=6;
+                       else if (j & 0x80) bits=7;
+                       else bits=0; /* should not happen */
+                       }
+               }
+       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);
-       if (bits == 0)
-               j=0;
-       else    j=8-bits;
-       *(p++)=(unsigned char)j;
+       *(p++)=(unsigned char)bits;
        d=a->data;
-       memcpy(p,d,a->length);
-       p+=a->length;
-       if (a->length > 0) p[-1]&=(0xff<<j);
+       memcpy(p,d,len);
+       p+=len;
+       if (len > 0) p[-1]&=(0xff<<bits);
        *pp=p;
        return(r);
        }
@@ -127,6 +150,12 @@ long length;
        if (len < 1) { i=ASN1_R_STRING_TOO_SHORT; goto err; }
 
        i= *(p++);
+       /* We do this to preserve the settings.  If we modify
+        * the settings, via the _set_bit function, we will recalculate
+        * on output */
+       ret->flags&= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); /* clear */
+       ret->flags|=(ASN1_STRING_FLAG_BITS_LEFT|(i&0x07)); /* set */
+
        if (len-- > 1) /* using one because of the bits left byte */
                {
                s=(unsigned char *)Malloc((int)len);
@@ -170,6 +199,8 @@ int value;
        v=1<<(7-(n&0x07));
        iv= ~v;
 
+       a->flags&= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); /* clear, set on write */
+
        if (a == NULL) return(0);
        if ((a->length < (w+1)) || (a->data == NULL))
                {