Allow memory bios to be read only and change PKCS#7 routines to use them.
authorDr. Stephen Henson <steve@openssl.org>
Thu, 19 Aug 1999 13:07:43 +0000 (13:07 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Thu, 19 Aug 1999 13:07:43 +0000 (13:07 +0000)
CHANGES
crypto/bio/bio.h
crypto/bio/bio_err.c
crypto/bio/bss_mem.c
crypto/pkcs7/pk7_doit.c

diff --git a/CHANGES b/CHANGES
index 7b6970e..e0b7cb6 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,18 @@
 
  Changes between 0.9.4 and 0.9.5  [xx XXX 1999]
 
+  *) Add a new flag to memory BIOs, BIO_FLAG_MEM_RDONLY. This marks the BIO
+     as "read only": it can't be written to and the buffer it points to will
+     not be freed. Reading from a read only BIO is much more efficient than
+     a normal memory BIO. This was added because there are several times when
+     an area of memory needs to be read from a BIO. The previous method was
+     to create a memory BIO and write the data to it, this results in two
+     copies of the data and an O(n^2) reading algorithm. There is a new
+     function BIO_new_mem_buf() which creates a read only memory BIO from
+     an area of memory. Also modified the PKCS#7 routines to use read only
+     memory BIOSs.
+     [Steve Henson]
+
   *) Bugfix: ssl23_get_client_hello did not work properly when called in
      state SSL23_ST_SR_CLNT_HELLO_B, i.e. when the first 7 bytes of
      a SSLv2-compatible client hello for SSLv3 or TLSv1 could be read,
index 58e0543..a05e0c2 100644 (file)
@@ -147,6 +147,11 @@ extern "C" {
 
 #define BIO_FLAGS_BASE64_NO_NL 0x100
 
+/* This is used with memory BIOs: it means we shouldn't free up or change the
+ * data in any way.
+ */
+#define BIO_FLAGS_MEM_RDONLY   0x200
+
 #define BIO_set_flags(b,f) ((b)->flags|=(f))
 #define BIO_get_flags(b) ((b)->flags)
 #define BIO_set_retry_special(b) \
@@ -526,6 +531,7 @@ long _far _loadds BIO_debug_callback(BIO *bio,int cmd,const char *argp,int argi,
 #endif
 
 BIO_METHOD *BIO_s_mem(void);
+BIO *BIO_new_mem_buf(void *buf, int len);
 BIO_METHOD *BIO_s_socket(void);
 BIO_METHOD *BIO_s_connect(void);
 BIO_METHOD *BIO_s_accept(void);
@@ -604,6 +610,7 @@ int BIO_printf(BIO *bio, ...);
 #define BIO_F_BIO_MAKE_PAIR                             121
 #define BIO_F_BIO_NEW                                   108
 #define BIO_F_BIO_NEW_FILE                              109
+#define BIO_F_BIO_NEW_MEM_BUF                           126
 #define BIO_F_BIO_NREAD                                         123
 #define BIO_F_BIO_NREAD0                                124
 #define BIO_F_BIO_NWRITE                                125
@@ -645,6 +652,7 @@ int BIO_printf(BIO *bio, ...);
 #define BIO_R_UNABLE_TO_LISTEN_SOCKET                   119
 #define BIO_R_UNINITIALIZED                             120
 #define BIO_R_UNSUPPORTED_METHOD                        121
+#define BIO_R_WRITE_TO_READ_ONLY_BIO                    126
 #define BIO_R_WSASTARTUP                                122
 
 #ifdef  __cplusplus
index cac78a7..136c348 100644 (file)
@@ -77,6 +77,7 @@ static ERR_STRING_DATA BIO_str_functs[]=
 {ERR_PACK(0,BIO_F_BIO_MAKE_PAIR,0),    "BIO_MAKE_PAIR"},
 {ERR_PACK(0,BIO_F_BIO_NEW,0),  "BIO_new"},
 {ERR_PACK(0,BIO_F_BIO_NEW_FILE,0),     "BIO_new_file"},
+{ERR_PACK(0,BIO_F_BIO_NEW_MEM_BUF,0),  "BIO_new_mem_buf"},
 {ERR_PACK(0,BIO_F_BIO_NREAD,0),        "BIO_nread"},
 {ERR_PACK(0,BIO_F_BIO_NREAD0,0),       "BIO_nread0"},
 {ERR_PACK(0,BIO_F_BIO_NWRITE,0),       "BIO_nwrite"},
@@ -121,6 +122,7 @@ static ERR_STRING_DATA BIO_str_reasons[]=
 {BIO_R_UNABLE_TO_LISTEN_SOCKET           ,"unable to listen socket"},
 {BIO_R_UNINITIALIZED                     ,"uninitialized"},
 {BIO_R_UNSUPPORTED_METHOD                ,"unsupported method"},
+{BIO_R_WRITE_TO_READ_ONLY_BIO            ,"write to read only bio"},
 {BIO_R_WSASTARTUP                        ,"wsastartup"},
 {0,NULL}
        };
index 7e749a5..d9a2280 100644 (file)
@@ -89,6 +89,26 @@ BIO_METHOD *BIO_s_mem(void)
        return(&mem_method);
        }
 
+BIO *BIO_new_mem_buf(void *buf, int len)
+{
+       BIO *ret;
+       BUF_MEM *b;
+       if (!buf) {
+               BIOerr(BIO_F_BIO_NEW_MEM_BUF,BIO_R_NULL_PARAMETER);
+               return NULL;
+       }
+       if(len == -1) len = strlen(buf);
+       if(!(ret = BIO_new(BIO_s_mem())) ) return NULL;
+       b = (BUF_MEM *)ret->ptr;
+       b->data = buf;
+       b->length = len;
+       b->max = len;
+       ret->flags |= BIO_FLAGS_MEM_RDONLY;
+       /* Since this is static data retrying wont help */
+       ret->num = 0;
+       return ret;
+}
+
 static int mem_new(BIO *bi)
        {
        BUF_MEM *b;
@@ -109,7 +129,10 @@ static int mem_free(BIO *a)
                {
                if ((a->init) && (a->ptr != NULL))
                        {
-                       BUF_MEM_free((BUF_MEM *)a->ptr);
+                       BUF_MEM *b;
+                       b = (BUF_MEM *)a->ptr;
+                       if(a->flags & BIO_FLAGS_MEM_RDONLY) b->data = NULL;
+                       BUF_MEM_free(b);
                        a->ptr=NULL;
                        }
                }
@@ -126,17 +149,18 @@ static int mem_read(BIO *b, char *out, int outl)
        bm=(BUF_MEM *)b->ptr;
        BIO_clear_retry_flags(b);
        ret=(outl > bm->length)?bm->length:outl;
-       if ((out != NULL) && (ret > 0))
-               {
+       if ((out != NULL) && (ret > 0)) {
                memcpy(out,bm->data,ret);
                bm->length-=ret;
                /* memmove(&(bm->data[0]),&(bm->data[ret]), bm->length); */
-               from=(char *)&(bm->data[ret]);
-               to=(char *)&(bm->data[0]);
-               for (i=0; i<bm->length; i++)
-                       to[i]=from[i];
+               if(b->flags & BIO_FLAGS_MEM_RDONLY) bm->data += ret;
+               else {
+                       from=(char *)&(bm->data[ret]);
+                       to=(char *)&(bm->data[0]);
+                       for (i=0; i<bm->length; i++)
+                               to[i]=from[i];
                }
-       else if (bm->length == 0)
+       else if (bm->length == 0)
                {
                if (b->num != 0)
                        BIO_set_retry_read(b);
@@ -158,6 +182,11 @@ static int mem_write(BIO *b, char *in, int inl)
                goto end;
                }
 
+       if(b->flags & BIO_FLAGS_MEM_RDONLY) {
+               BIOerr(BIO_F_MEM_WRITE,BIO_R_WRITE_TO_READ_ONLY_BIO);
+               goto end;
+       }
+
        BIO_clear_retry_flags(b);
        blen=bm->length;
        if (BUF_MEM_grow(bm,blen+inl) != (blen+inl))
@@ -178,9 +207,15 @@ static long mem_ctrl(BIO *b, int cmd, long num, char *ptr)
        switch (cmd)
                {
        case BIO_CTRL_RESET:
-               if (bm->data != NULL)
-                       memset(bm->data,0,bm->max);
-               bm->length=0;
+               if (bm->data != NULL) {
+                       /* For read only case reset to the start again */
+                       if(b->flags & BIO_FLAGS_MEM_RDONLY) 
+                                       bm->data -= bm->max - bm->length;
+                       else {
+                               memset(bm->data,0,bm->max);
+                               bm->length=0;
+                       }
+               }
                break;
        case BIO_CTRL_EOF:
                ret=(long)(bm->length == 0);
index dee81b5..af66511 100644 (file)
@@ -216,30 +216,22 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio)
                btmp=NULL;
                }
 
-       if (bio == NULL) /* ??????????? */
-               {
+       if (bio == NULL) {
                if (p7->detached)
                        bio=BIO_new(BIO_s_null());
-               else
-                       {
-                       bio=BIO_new(BIO_s_mem());
-                       /* We need to set this so that when we have read all
-                        * the data, the encrypt BIO, if present, will read
-                        * EOF and encode the last few bytes */
-                       BIO_set_mem_eof_return(bio,0);
-
+               else {
                        if (PKCS7_type_is_signed(p7) &&
-                               PKCS7_type_is_data(p7->d.sign->contents))
-                               {
+                               PKCS7_type_is_data(p7->d.sign->contents)) {
                                ASN1_OCTET_STRING *os;
-
                                os=p7->d.sign->contents->d.data;
-                               if (os->length > 0)
-                                       BIO_write(bio,(char *)os->data,
-                                               os->length);
-                               }
+                               if (os->length > 0) bio = 
+                                       BIO_new_mem_buf(os->data, os->length);
+                       } else {
+                               bio=BIO_new(BIO_s_mem());
+                               BIO_set_mem_eof_return(bio,0);
                        }
                }
+       }
        BIO_push(out,bio);
        bio=NULL;
        if (0)
@@ -430,6 +422,7 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert)
                }
        else 
                {
+#if 0
                bio=BIO_new(BIO_s_mem());
                /* We need to set this so that when we have read all
                 * the data, the encrypt BIO, if present, will read
@@ -438,6 +431,14 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert)
 
                if (data_body->length > 0)
                        BIO_write(bio,(char *)data_body->data,data_body->length);
+#else
+               if (data_body->length > 0)
+                     bio = BIO_new_mem_buf(data_body->data,data_body->length);
+               else {
+                       bio=BIO_new(BIO_s_mem());
+                       BIO_set_mem_eof_return(bio,0);
+               }
+#endif
                }
        BIO_push(out,bio);
        bio=NULL;
@@ -611,8 +612,17 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio)
                        goto err;
                        }
                BIO_get_mem_ptr(btmp,&buf_mem);
+               /* Mark the BIO read only then we can use its copy of the data
+                * instead of making an extra copy.
+                */
+               BIO_set_flags(btmp, BIO_FLAGS_MEM_RDONLY);
+               BIO_set_mem_eof_return(btmp, 0);
+               os->data = (unsigned char *)buf_mem->data;
+               os->length = buf_mem->length;
+#if 0
                ASN1_OCTET_STRING_set(os,
                        (unsigned char *)buf_mem->data,buf_mem->length);
+#endif
                }
        if (pp != NULL) Free(pp);
        pp=NULL;