Synchronise the VMS build with the Unix one.
[oweals/openssl.git] / crypto / asn1 / a_bitstr.c
index eb99ebca2f78de577ece57104cb8e63b64c5bbfe..7013a407ad68385d0f82c27ec6d4aed864f5d4ea 100644 (file)
@@ -1,5 +1,5 @@
 /* crypto/asn1/a_bitstr.c */
-/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
  * All rights reserved.
  *
  * This package is an SSL implementation written
 
 #include <stdio.h>
 #include "cryptlib.h"
-#include "asn1.h"
+#include <openssl/asn1.h>
 
-/* ASN1err(ASN1_F_ASN1_STRING_NEW,ASN1_R_STRING_TOO_SHORT);
- * ASN1err(ASN1_F_D2I_ASN1_BIT_STRING,ASN1_R_EXPECTING_A_BIT_STRING);
- */
+ASN1_BIT_STRING *ASN1_BIT_STRING_new(void)
+{ return M_ASN1_BIT_STRING_new(); }
+
+void ASN1_BIT_STRING_free(ASN1_BIT_STRING *x)
+{ M_ASN1_BIT_STRING_free(x); }
+
+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,len,V_ASN1_BIT_STRING,V_ASN1_UNIVERSAL);
+               i2c_ASN1_BIT_STRING(a, pp);     
+       }
+       return ret;
+}
 
-int i2d_ASN1_BIT_STRING(a,pp)
-ASN1_BIT_STRING *a;
-unsigned char **pp;
+int i2c_ASN1_BIT_STRING(ASN1_BIT_STRING *a, unsigned char **pp)
        {
-       int ret,j,r,bits;
+       int ret,j,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;
-       r=ASN1_object_size(0,ret,V_ASN1_BIT_STRING);
-       if (pp == NULL) return(r);
+       len=a->length;
+       ret=1+len;
+       if (pp == NULL) return(ret);
+
+       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;
        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);
+       return(ret);
        }
 
-ASN1_BIT_STRING *d2i_ASN1_BIT_STRING(a, pp, length)
-ASN1_BIT_STRING **a;
-unsigned char **pp;
-long length;
-       {
-       ASN1_BIT_STRING *ret=NULL;
-       unsigned char *p,*s;
+
+/* 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)
+{
+       unsigned char *p;
        long len;
-       int inf,tag,xclass;
        int i;
-
-       if ((a == NULL) || ((*a) == NULL))
-               {
-               if ((ret=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);
@@ -125,11 +154,40 @@ long length;
                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
+        * 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);
+               s=(unsigned char *)OPENSSL_malloc((int)len);
                if (s == NULL)
                        {
                        i=ERR_R_MALLOC_FAILURE;
@@ -143,7 +201,7 @@ long length;
                s=NULL;
 
        ret->length=(int)len;
-       if (ret->data != NULL) Free((char *)ret->data);
+       if (ret->data != NULL) OPENSSL_free(ret->data);
        ret->data=s;
        ret->type=V_ASN1_BIT_STRING;
        if (a != NULL) (*a)=ret;
@@ -152,7 +210,50 @@ long length;
 err:
        ASN1err(ASN1_F_D2I_ASN1_BIT_STRING,i);
        if ((ret != NULL) && ((a == NULL) || (*a != ret)))
-               ASN1_BIT_STRING_free(ret);
+               M_ASN1_BIT_STRING_free(ret);
        return(NULL);
        }
 
+/* These next 2 functions from Goetz Babin-Ebell <babinebell@trustcenter.de>
+ */
+int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *a, int n, int value)
+       {
+       int w,v,iv;
+       unsigned char *c;
+
+       w=n/8;
+       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))
+               {
+               if (!value) return(1); /* Don't need to set */
+               if (a->data == NULL)
+                       c=(unsigned char *)OPENSSL_malloc(w+1);
+               else
+                       c=(unsigned char *)OPENSSL_realloc(a->data,w+1);
+               if (c == NULL) return(0);
+               if (w+1-a->length > 0) memset(c+a->length, 0, w+1-a->length);
+               a->data=c;
+               a->length=w+1;
+       }
+       a->data[w]=((a->data[w])&iv)|v;
+       while ((a->length > 0) && (a->data[a->length-1] == 0))
+               a->length--;
+       return(1);
+       }
+
+int ASN1_BIT_STRING_get_bit(ASN1_BIT_STRING *a, int n)
+       {
+       int w,v;
+
+       w=n/8;
+       v=1<<(7-(n&0x07));
+       if ((a == NULL) || (a->length < (w+1)) || (a->data == NULL))
+               return(0);
+       return((a->data[w]&v) != 0);
+       }
+