Commit 8484721a authored by Dr. Stephen Henson's avatar Dr. Stephen Henson
Browse files

Allow memory bios to be read only and change PKCS#7 routines to use them.

parent de1915e4
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -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,
+8 −0
Original line number Diff line number Diff line
@@ -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
+2 −0
Original line number Diff line number Diff line
@@ -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}
	};
+46 −11
Original line number Diff line number Diff line
@@ -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); */
		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)
		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);
+27 −17
Original line number Diff line number Diff line
@@ -216,27 +216,19 @@ 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);
			}
		}
	}
@@ -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;