diff --git a/CHANGES b/CHANGES index 7b6970eb458f25aaf7656523e0e1d1bb750233e7..e0b7cb6b7f63173131095359fe1eba68ecda872c 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 58e0543504be7289619e5428e1fd43a1469948df..a05e0c2eacdb7eb8aaecf9f46d13b5ca364aeaef 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 cac78a7fc040bcf5e029b6e1ceea617b711b3b3d..136c348af7e3600ad89756bdb62b1654a32703d6 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 7e749a503ef370913b87c8675a062374470d5ad2..d9a2280d8f0994a87608eec2c74e477f1eec8859 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; ilength; 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; ilength; 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 dee81b547adde3f20c0cb652f587d1631fabdb4e..af66511ebacec7f7e94bbeb3bfe1801ab898514c 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;