aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGES12
-rw-r--r--crypto/bio/bio.h8
-rw-r--r--crypto/bio/bio_err.c2
-rw-r--r--crypto/bio/bss_mem.c57
-rw-r--r--crypto/pkcs7/pk7_doit.c44
5 files changed, 95 insertions, 28 deletions
diff --git a/CHANGES b/CHANGES
index 7b6970eb45..e0b7cb6b7f 100644
--- 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,
diff --git a/crypto/bio/bio.h b/crypto/bio/bio.h
index 58e0543504..a05e0c2eac 100644
--- a/crypto/bio/bio.h
+++ b/crypto/bio/bio.h
@@ -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
diff --git a/crypto/bio/bio_err.c b/crypto/bio/bio_err.c
index cac78a7fc0..136c348af7 100644
--- a/crypto/bio/bio_err.c
+++ b/crypto/bio/bio_err.c
@@ -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}
};
diff --git a/crypto/bio/bss_mem.c b/crypto/bio/bss_mem.c
index 7e749a503e..d9a2280d8f 100644
--- a/crypto/bio/bss_mem.c
+++ b/crypto/bio/bss_mem.c
@@ -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);
diff --git a/crypto/pkcs7/pk7_doit.c b/crypto/pkcs7/pk7_doit.c
index dee81b547a..af66511eba 100644
--- a/crypto/pkcs7/pk7_doit.c
+++ b/crypto/pkcs7/pk7_doit.c
@@ -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;